Skip to content

Latest commit

 

History

History
254 lines (214 loc) · 6.41 KB

tests.md

File metadata and controls

254 lines (214 loc) · 6.41 KB

Testing

Jest

To test a component which use RNCamera, you need to create a react-native-camera.js file inside your mocks folder on the root of your project with the following content:

import React from 'react'


const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))

export class RNCamera extends React.Component {
  static Constants = {
    Aspect: {},
    BarCodeType: {},
    Type: { back: 'back', front: 'front' },
    CaptureMode: {},
    CaptureTarget: {},
    CaptureQuality: {},
    Orientation: {},
    FlashMode: {},
    TorchMode: {},
  }

  takePictureAsync = async () => {
    await timeout(2000)
    return {
      base64: 'base64string',
    }
  }

  render() {
    return null
  }
}

export default RNCamera

You don't need to do anything else in your test, because Jest will use the mock in your test instead of the native module.

Example

We are going to create a component which uses RNCamera which two simple features:

  • Take a photo
  • Change camera between front or back

The custom component PhotoCamera is the following:

import React from 'react'
import { View, TouchableOpacity, StyleSheet, Dimensions } from 'react-native'
import { RNCamera } from 'react-native-camera'
import Icon from 'react-native-vector-icons/FontAwesome'


const styles = StyleSheet.create({
  container: {
    flex: 1,
    display: 'flex',
    flexDirection: 'column',
    backgroundColor: 'black',
  },
  preview: {
    flex: 1,
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
  topButtons: {
    flex: 1,
    width: Dimensions.get('window').width,
    alignItems: 'flex-start',
  },
  bottomButtons: {
    flex: 1,
    width: Dimensions.get('window').width,
    justifyContent: 'flex-end',
    alignItems: 'center',
  },

  flipButton: {
    flex: 1,
    marginTop: 20,
    right: 20,
    alignSelf: 'flex-end',
  },
  recordingButton: {
    marginBottom: 10,
  },
})

class PhotoCamera extends React.PureComponent {
  state = {
    type: RNCamera.Constants.Type.back,
  }

  flipCamera = () =>
    this.setState({ type: this.state.type === RNCamera.Constants.Type.back ? RNCamera.Constants.Type.front : RNCamera.Constants.Type.back })

  takePhoto = async () => {
    const { onTakePhoto } = this.props
    const options = {
      quality: 0.5,
      base64: true,
      width: 300,
      height: 300,
    }
    const data = await this.camera.takePictureAsync(options)
    onTakePhoto(data.base64)
  }
  render() {
    const { type } = this.state
    return (
      <View style={styles.container}>
        <RNCamera
          ref={(cam) => {
            this.camera = cam
          }}
          type={type}
          style={styles.preview}
        />
        <View style={styles.topButtons}>
          <TouchableOpacity onPress={this.flipCamera} style={styles.flipButton}>
            <Icon name="refresh" size={35} color="orange" />
          </TouchableOpacity>
        </View>
        <View style={styles.bottomButtons}>
          <TouchableOpacity onPress={this.takePhoto} style={styles.recordingButton}>
            <Icon name="camera" size={50} color="orange" />
          </TouchableOpacity>
        </View>
      </View>
    )
  }
}

export default PhotoCamera

And here is our test to check if it renders properly:

import React from 'react'
import Adapter from 'enzyme-adapter-react-16'
import { shallow, configure } from 'enzyme'
import MyPhotoCamera from './'


configure({ adapter: new Adapter() })

describe('PhotoCamera Tests', () => {
  test('renders correctly', () => {
    const wrapper = shallow(<MyPhotoCamera />)
    expect(wrapper).toMatchSnapshot()
  })
})

Also, here is the complete test of the whole component with 100% coverage:

import React from 'react'
import { TouchableOpacity } from 'react-native'
import Adapter from 'enzyme-adapter-react-16'
import { shallow, configure, mount } from 'enzyme'
import PhotoCamera from '../'


const { JSDOM } = require('jsdom')


const jsdom = new JSDOM()
const { window } = jsdom

function copyProps(src, target) {
  const props = Object.getOwnPropertyNames(src)
    .filter(prop => typeof target[prop] === 'undefined')
    .map(prop => Object.getOwnPropertyDescriptor(src, prop))
  Object.defineProperties(target, props)
}

global.window = window
global.document = window.document
global.navigator = {
  userAgent: 'node.js',
}
copyProps(window, global)

// Ignore React Web errors when using React Native
// but still show relevant errors
const suppressedErrors = /(React does not recognize the.*prop on a DOM element|Unknown event handler property|is using uppercase HTML|Received `true` for a non-boolean attribute `accessible`|The tag.*is unrecognized in this browser)|is using incorrect casing|Received `true` for a non-boolean attribute `enabled`/
const realConsoleError = console.error // eslint-disable-line
// eslint-disable-next-line
console.error = message => {
  if (message.match(suppressedErrors)) {
    return
  }
  realConsoleError(message)
}

configure({ adapter: new Adapter() })

describe('PhotoCamera Tests', () => {
  test('renders correctly', () => {
    const wrapper = shallow(<PhotoCamera />)
    expect(wrapper).toMatchSnapshot()
  })
  test('initial state should be back camera', () => {
    const wrapper = shallow(<PhotoCamera />)
    expect(wrapper.state().type).toBe('back')
  })
  test('should flip the camera from back to front', () => {
    const wrapper = shallow(<PhotoCamera />)
    expect(wrapper.state().type).toBe('back')
    wrapper
      .find(TouchableOpacity)
      .first()
      .props()
      .onPress()
    expect(wrapper.state().type).toBe('front')
  })

  test('should flip the camera from front to back if touch flip button and curren state is ', () => {
    const wrapper = shallow(<PhotoCamera />)
    wrapper.setState({
      type: 'front',
    })
    wrapper.update()
    wrapper
      .find(TouchableOpacity)
      .first()
      .props()
      .onPress()
    expect(wrapper.state().type).toBe('back')
  })

  test('should have a reference to the React Native Camera module', () => {
    const wrapper = mount(<PhotoCamera />)
    expect(wrapper.instance().camera).toBeDefined()
  })

  test('test onPress functionality', async () => {
    const onTakePhotoEvent = jest.fn(data => data)
    const wrapper = mount(<PhotoCamera onTakePhoto={onTakePhotoEvent} />)
    await wrapper
      .find(TouchableOpacity)
      .at(1)
      .props()
      .onPress()
    expect(onTakePhotoEvent.mock.calls.length).toBe(1)
  })
})