A voyage into testing that fickle devil known as JavaScript... and beyond!
readability etc.
My perspective.
Sooo... lots of React Native
but seriously...
How do they work?
If you're doing the same thing in two places, DRY your code."
- Everyone
If you're doing two things in one place, split your code."
- Gant (and probably everyone, too)
... yes, but...
"-ish"
"-ish"
"-ish"
Do some thing!
Did it do the thing?
But be functional!!!!
Fan of AVA? Try this article
import React from "react"
import { MagicButton } from "../src/components/magicButton"
import renderer from "react-test-renderer"
test("MagicButton has onPress fn", () => {
let x = 0
const buttonInstance = renderer
.create(<MagicButton onPress={() => x++} />)
.getInstance()
expect(buttonInstance.handleCrazyPress).toBeDefined()
expect(x).toBe(0)
buttonInstance.props.handleCrazyPress()
expect(x).toBe(1)
})
function setAnswer(question, answer) {
fireEvent.changeText(question, answer);
}
test('should verify two questions', () => {
const { getAllByType, getByText } = render(<QuestionsBoard {...props} />);
const allQuestions = getAllByType(Question);
setAnswer(allQuestions[0], 'a1');
setAnswer(allQuestions[1], 'a2');
fireEvent.press(getByText('submit'));
expect(props.verifyQuestions).toBeCalledWith({
'1': { q: 'q1', a: 'a1' },
'2': { q: 'q2', a: 'a2' },
});
});
// setupJest.js or similar file
global.fetch = require('jest-fetch-mock')
jest-fetch-mock
custom mock
const API = require('mockAPI')
JEST automatically uses the mock folder
describe("My Date() Tests", () => {
beforeEach(() => {
MockDate.set("2012-12-12T00:00:00.000Z")
})
afterEach(() => {
MockDate.reset()
})
...
})
import React from 'react'
import Mole from '../../src/views/Mole/mole'
import renderer from 'react-test-renderer'
test('Inactive Mole Press', () => {
const moleInstance = renderer.create(<Mole />).getInstance()
moleInstance.handlePressIn()
expect(moleInstance.state.currentImage.testUri).toContain('hole')
})
Passes on Mac - Fails on Windows
Forcing integration can be false security.
UNLESS
const temp = createAmazingObject('test', 'φ', 1.61803)
expect(temp).toMatchSnapshot()
import initStoryshots from "@storybook/addon-storyshots"
initStoryshots({
configPath: "./storybook",
framework: "react-native",
})
Now all storybook stories are snapshot tests
import { testStateMachine } from 'react-automata'
import { App } from '../App'
test('all state snapshots', () => {
testStateMachine(App, { fixtures })
})
Assure your app code handles all combinations of state you've identified!
Dependency injected middleware combinations
sleep(4)
sleep(9)
sleep(12)
sleep(17)
Example App:
Try it yourself! Especially the time travel.
"rehab": "detox build && detox test"
Set time for setup!
describe("Example", () => {
beforeEach(async () => {
// await device.reloadReactNative()
await device.launchApp({ newInstance: true })
})
it("should have packing list screen", async () => {
await expect(element(by.id("packingListScreen"))).toBeVisible()
})
it("should have an input screen", async () => {
await element(by.text("Input")).tap()
await expect(element(by.id("listInputScreen"))).toBeVisible()
})
})
Given that accessibilityLabel is an outwardly-facing string that is actually used by accessibility screen readers (and should be localized to the device user's language), Apple now provides an alternate property (iOS 5+) that is specifically intended for UI Automation purposes"
describe("List Input Test", () => {
beforeEach(async () => {
// await device.reloadReactNative()
await device.launchApp({ newInstance: true })
await element(by.text("Input")).tap()
})
it("should have list input screen", async () => {
await expect(element(by.id("listInputScreen"))).toBeVisible()
})
it("should have a list input component", async () => {
await expect(element(by.id("inputField"))).toBeVisible()
await element(by.id("inputField")).replaceText("Socks")
await element(by.text("Add item to List")).tap()
await element(by.text("List")).tap()
await expect(element(by.text("Socks"))).toBeVisible()
})
})
When you upgrade React Native, you can break Detox tests.
When upgrade Detox, you can break Detox tests.
React
https://github.com/evcohen/eslint-plugin-jsx-a11y
by Evan Cohen @beefancohen
React Native
https://github.com/FormidableLabs/eslint-plugin-react-native-a11y
by Jen Luker @knitcodemonkey
Common Testing Stack
"Stop saying 'You forgot to ...' in code review"
Write JavaScript!
protecting REST API Calls Backwards
Enforce API structure with Schemas
https://developers.google.com/speed/pagespeed/insights/
Performance API of your particular browser
(performance.mark / performance.measure)
DRY code is maintainable code
use https://codecov.io/ or others
greenkeeper.io
updtr
Unused!? try npm-check
Madge Graphs
$ yarn madge --circular path/src/
$ yarn madge --extensions ts --circular src/
works with most common testing libs
check(
property(
gen.int, gen.int,
(a, b) => a + b >= a && a + b >= b
)
)
Simplest failcase
{ result: false,
failingSize: 2,
numTests: 3,
fail: [ 2, -1 ],
shrunk:
{ totalNodesVisited: 2,
depth: 1,
result: false,
smallest: [ 0, -1 ]
}
}
Find the ones that fit your project, and use them!
The question is:
"What needs to be durable and effective for your software?"
GantLaborde.com
@GantLaborde