Testing & React Native

Lessons from the Battlefield

Aaron Greenwald

Survey
01 / Once Upon A Time
A long, long time ago
(About 1.5 years ago)
(That's 10.5 dog years)
(And 10.510000000 JS ecosystem years)
BOOOORING!
02 / Valiant & Brave
Credit: Timeout
React Native 0.13
Android Support
(Yeah, ok)
Fast & Furious Development
03 / Taming the Wild
How Can We TDD?
Testing Pyramid
Enzyme
Enzyme Drivers
                
beforeEach(() => {
  initDriver();
});
it('should render footer when loading', () => {
  driver.render({contacts: [], isLoading: true});
  let footer = driver.renderFooter();
  expect(footer.props.testID).toEqual('activity-indicator');

  driver.render({contacts: [], isLoading: false});
  footer = driver.renderFooter();
  expect(footer).toBe(null);
});
                
            
                
function initDriver() {
  driver = new ContactListDriver({
    path: 'contact-list/contact-list.mobile.component',
    mocks: {
      'mobx-react/native': {observer: x => x},
      './some-component': createMockReactComponent(),
      'wix-react-native-ui-lib': uiLibMock
    }
  });
}
                
            
                

class ContactListDriver extends RNDriver {
  get contacts() {
    return this.propsOf('contacts').dataSource._dataBlob;
  }
  ...

  renderFooter() {
    return this.propsOf('contacts').renderFooter();
  }
}
                
            
Mocks, Mocks, Mocks
Shallow vs Deep Rendering
Refactoring
Architecture Matters
Jest
Appium
				
xit('should not allow sending an empty message',
                    test.specAsync(async () => {

  //check that the value is not sent if the message is empty
  await driver.safeClick('sendButton');
  await test.expectElementToNotExist('activity-guid');
  await test.expectElementToNotExist('activity-1001');

  //now type something, delete it and try to send
  //again to check that it is not sent either
  await driver.typeOnKeyboard('a');
  await driver.tapKeyboardDelete(1);
  await driver.sleep(500);
  await driver.safeClick('sendButton', 1000);
  await test.expectElementToNotExist('activity-guid');
  await test.expectElementToNotExist('activity-1001');
}));
				
			
				
wd.addPromiseChainMethod('typeOnKeyboard', function (val) {
  let t = this.execute(
     'target.frontMostApp().keyboard()'
     ).sleep(750);
  for (let i = 0; i < val.length; i++) {
    t = t.sleep(150).execute(
      `target
        .frontMostApp()
        .keyboard()
        .typeString('${val[i]}')`
    );
  }
  return t;
});
				
			
				
...
expectElementToNotExist: async testId => {
  let element;
  for (let i = 0; i < 20; i++) {
    element = await driver.getElementIfExists(testId, 50);
    if (element) {
        // if it's still there check back in a little bit
        await driver.sleep(50);
    } else {
      element = undefined;
      break;
    }
  }
  expect({element, testId}).not.toBeAValidElement();
},
...

				
			
WD
IWD
WTF
Most Important ThingTM
Stable
Fast
Reframing the Problem
E2E UI Automation
github.com/wix/detox
Stable
Fast
RN-Friendly
04 / Now What??
(Detox for Android)

Clueless

Beginner

Cynic

Expert

Stability

Lots of Options

Few Excuses

Thank You
E2E
Component
Unit