pixielabs / cavy
- воскресенье, 12 марта 2017 г. в 03:12:22
JavaScript
An integration test framework for React Native.
Cavy is a cross-platform integration test framework for React Native, by Pixie Labs.
Cavy (ab)uses React ref
generating functions to give you the ability to refer
to, and simulate actions upon, deeply nested components within your
application. Unlike a tool like enzyme
which uses a simulated renderer, Cavy runs within your live application as it
is running on a host device (e.g. your Android or iOS simulator).
This allows you to do far more accurate integration testing than if you run your React app within a simulated rendering environment.
We built Cavy because, at the time of writing, React Native had only a handful of testing approaches available:
Cavy fits in between shallow-render testing and testing within your native environment.
Cavy provides 3 tools to let you run integration tests:
<Tester>
component you wrap around your entire app to make the test hook
store available, and autorun your test cases on boot.To get started using Cavy, install it using yarn
:
yarn add cavy --dev
or npm
:
npm i --save-dev cavy
Check out the sample app for example usage. Here it is running:
Add 'hooks' to any components you want to test by adding a ref
and using the
generateTestHook
function.
generateTestHook
takes a string as its first argument - this is the identifier
to be used in tests. It takes an optional second argument in case you want to
set your own ref
generating function.
Stateless functional components cannot be assigned a ref
since they don't have
instances. Use the wrap
function to wrap them inside a non-stateless component.
import React, { Component } from 'react';
import { TextInput } from 'react-native';
import { FuncComponent } from 'somewhere';
import { hook, wrap } from 'cavy';
class Scene extends Component {
render() {
const WrappedComponent = wrap(FuncComponent);
return (
<TextInput
ref={this.props.generateTestHook('Scene.TextInput')}
onChangeText={...}
/>
<WrappedComponent
ref={this.props.generateTestHook('Scene.Component')}
onPress={...}
/>
);
}
}
const TestableScene = hook(Scene);
export default TestableScene;
Using your component identifiers, write your spec functions. We suggest saving
these in a spec folder, naming them something like ./specs/AppSpec.js
.
export default function(spec) {
spec.describe('My feature', function() {
spec.it('works', async function() {
await spec.fillIn('Scene.TextInput', 'some string')
await spec.press('Scene.button');
await spec.exists('NextScene')
});
});
}
See below for a list of currently available spec helper functions.
Import Tester
, TestHookStore
and your specs in your top-level JS file
(typically this is your index.{ios,android}.js
files), and instantiate a new
TestHookStore
.
Wrap your app in a Tester component, passing in the TestHookStore
and an array
containing your imported spec functions.
Optional props:
waitTime
- Integer, the time in milliseconds that your tests should
wait to find specified 'hooked' components.
Set to 2000
(2 seconds) by default.
clearAsyncStorage
- Boolean, set this to true
to clear AsyncStorage between
each test e.g. to remove a logged in user.
Set to false
by default.
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import { Tester, TestHookStore } from 'cavy';
import AppSpec from './specs/AppSpec';
import App from './app';
const testHookStore = new TestHookStore();
export default class AppWrapper extends Component {
render() {
return (
<Tester specs={[AppSpec]} store={testHookStore} waitTime={4000}>
<App />
</Tester>
);
}
}
AppRegistry.registerComponent('AppWrapper', () => AppWrapper);
Congratulations! You are now all set up to start testing your app with Cavy.
Your tests will run automatically when you run your app using either:
$ react-native run-ios
or
$ react-native run-android
fillIn(identifier, str)
- fills in the identified 'TextInput'-compatible
component with the provided string (str). Your component must respond to the
property onChangeText
.
press(identifier)
- presses the identified component. Your component must
respond to the property onPress
.
pause(integer)
- pauses the running test for the length of time, specified in
milliseconds (integer). This is useful if you need to allow time for a response
to be received before progressing.
exists(identifier)
- returns true
if the component can be identified (i.e.
is currently on screen).
notExists(identifier)
- as above, but checks for the absence of the
component.
findComponent(identifier)
- returns the identified component. This function
should be used if your testable component does not respond to either
onChangeText
or onPress
, for example:
picker = await spec.findComponent('Scene.modalPicker');
picker.open();