Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add snapshot test suite for React Native support #328

Merged
merged 8 commits into from
Mar 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions other/react-native/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["env", "react-native"]
}
43 changes: 43 additions & 0 deletions other/react-native/__tests__/__snapshots__/render-tests.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm normally not a huge fan of huge snapshots (learn more). But I think this is ok because I don't think we plan on making changes that would affect this snapshot very often anyway. But if there's a way we can avoid these snapshots by making more explicit assertions I think I'd be happier with that.

Copy link
Contributor Author

@eliperkins eliperkins Feb 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I tried thinking of a better way to get here, instead of using snapshots, but I'm unsure of what other methods we could use to test the React Native renderer.

We could emulate the Preact tests and use a spy to ensure that render successfully gets called, but I don't think that's any better than these snapshots.

I'll see if I can come up some better assertions here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up writing some tests that were similar to those Preact tests and I feel like it's much clearer as to what we're testing now! 216c531

Let me know what you think.


exports[`renders with React Native components 1`] = `
<View>
<TextInput
allowFontScaling={true}
aria-activedescendant={null}
aria-autocomplete="list"
aria-expanded={false}
autoComplete="off"
id="downshift-0-input"
onBlur={[Function]}
onChangeText={[Function]}
onKeyDown={[Function]}
role="combobox"
value=""
/>
<View>
<Text
accessible={true}
allowFontScaling={true}
ellipsizeMode="tail"
id="downshift-0-item-0"
onMouseDown={[Function]}
onMouseMove={[Function]}
onPress={[Function]}
>
foo
</Text>
<Text
accessible={true}
allowFontScaling={true}
ellipsizeMode="tail"
id="downshift-0-item-1"
onMouseDown={[Function]}
onMouseMove={[Function]}
onPress={[Function]}
>
bar
</Text>
</View>
</View>
`;
88 changes: 88 additions & 0 deletions other/react-native/__tests__/render-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* eslint-disable react/prop-types */
// eslint-disable-next-line import/no-unassigned-import
import {Text, TextInput, View} from 'react-native'
import React from 'react'

// Note: test renderer must be required after react-native.
import TestRenderer from 'react-test-renderer'

import Downshift from '../../../dist/downshift.native.cjs'

test('renders with React Native components', () => {
const RootView = ({innerRef, ...rest}) => <View ref={innerRef} {...rest} />
const renderSpy = jest.fn(({getRootProps, getInputProps, getItemProps}) => (
<RootView {...getRootProps({refKey: 'innerRef'})}>
<TextInput {...getInputProps()} />
<View>
<Text {...getItemProps({item: 'foo', index: 0})}>foo</Text>
<Text {...getItemProps({item: 'bar', index: 1})}>bar</Text>
</View>
</RootView>
))
const element = <Downshift render={renderSpy} />
const renderer = TestRenderer.create(element)
expect(renderSpy).toHaveBeenCalledWith(
expect.objectContaining({
isOpen: false,
highlightedIndex: null,
selectedItem: null,
inputValue: '',
}),
)
const tree = renderer.toJSON()
expect(tree).toMatchSnapshot()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could remove this snapshot, but I think ensuring that we render the basic set of React Native components here, while applying the functions from Downshift, is a fair trade-off for using a snapshot.

})

test('can use children instead of render prop', () => {
const RootView = ({innerRef, ...rest}) => <View ref={innerRef} {...rest} />
const renderSpy = jest.fn(({getRootProps, getInputProps, getItemProps}) => (
<RootView {...getRootProps({refKey: 'innerRef'})}>
<TextInput {...getInputProps()} />
<View>
<Text {...getItemProps({item: 'foo', index: 0})}>foo</Text>
<Text {...getItemProps({item: 'bar', index: 1})}>bar</Text>
</View>
</RootView>
))
const element = <Downshift>{renderSpy}</Downshift>
TestRenderer.create(element)
expect(renderSpy).toHaveBeenCalledTimes(1)
})

test('calls onChange when TextInput changes values', () => {
const onChange = jest.fn()
const Input = jest.fn(props => <TextInput {...props} />)

const RootView = ({innerRef, ...rest}) => <View ref={innerRef} {...rest} />
const renderSpy = jest.fn(({getRootProps, getInputProps, getItemProps}) => (
<RootView {...getRootProps({refKey: 'innerRef'})}>
<Input {...getInputProps({onChange})} />
<View>
<Text {...getItemProps({item: 'foo', index: 0})}>foo</Text>
<Text {...getItemProps({item: 'bar', index: 1})}>bar</Text>
</View>
</RootView>
))
const element = <Downshift>{renderSpy}</Downshift>
TestRenderer.create(element)
expect(renderSpy).toHaveBeenCalledTimes(1)

const [[firstArg]] = Input.mock.calls
expect(firstArg).toMatchObject({
// TODO: We shouldn't need to know about the internals of how we're affecting the TextInput and what props we're supplying.
// See https://github.com/paypal/downshift/issues/361
onChangeText: expect.any(Function),
})
const fakeEvent = 'foobar'
firstArg.onChangeText(fakeEvent)

expect(onChange).toHaveBeenCalledTimes(1)
expect(onChange).toHaveBeenCalledWith(fakeEvent)
})

/*
eslint
react/prop-types: 0,
import/extensions: 0,
import/no-unresolved: 0
*/
10 changes: 10 additions & 0 deletions other/react-native/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const jestConfig = require('kcd-scripts/config').jest

module.exports = Object.assign(jestConfig, {
preset: 'react-native',
testEnvironment: 'node',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This song and dance felt pretty gnarly, but this is the base config I've found that allows for sharing of kcd-scripts/config and supporting React Native in react-test-renderer. This ensures that the react-native module gets transformed by Babel, tells Jest to look for sources and tests from the root, but then scopes tests down to only other/react-native/__tests__.

transformIgnorePatterns: ['<rootDir>/node_modules/(?!react-native)/'],
rootDir: '../../',
roots: ['.'],
testMatch: ['<rootDir>/other/react-native/__tests__/**/*.js?(x)'],
})
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"test:ssr": "kcd-scripts test --config other/ssr/jest.config.js --no-watch",
"test:update": "npm run test:cover -s -- --updateSnapshot",
"test:ts": "tsc --noEmit -p ./tsconfig.json",
"test:build": "kcd-scripts test --config other/misc-tests/jest.config.js --no-watch",
"test:build": "jest --projects other/misc-tests other/react-native",
"test:cypress:dev": "npm-run-all --parallel --race storybook cy:open",
"pretest:cypress": "npm run storybook:build --silent",
"test:cypress": "npm-run-all --parallel --race storybook:serve cy:run",
Expand Down Expand Up @@ -61,6 +61,9 @@
},
"devDependencies": {
"@storybook/react": "^3.3.14",
"babel-jest": "^22.2.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react-native": "^4.0.0",
"cross-env": "^5.1.3",
"cypress": "^2.0.3",
"enzyme": "^3.3.0",
Expand All @@ -76,6 +79,7 @@
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-native": "^0.53.0",
"react-test-renderer": "^16.2.0",
"serve": "^6.4.11",
"typescript": "^2.7.2"
Expand Down