Skip to content

Instantly share code, notes, and snippets.

@devboell
Last active August 13, 2018 05:15
Show Gist options
  • Save devboell/971c5477532fcae674c49110ab720ceb to your computer and use it in GitHub Desktop.
Save devboell/971c5477532fcae674c49110ab720ceb to your computer and use it in GitHub Desktop.
apollo integration testing approach

This is in response to a stackoverflow question by Daniel Ocampo, https://stackoverflow.com/questions/45700550/how-to-use-a-mocked-data-with-react-apollo-for-tests/46215295#comment90554677_46215295

Disclaimer: this is just an approach I came up with, and by no means do I suggest this is the recommended way.

I have selected 4 files from my fretboard-trainer project https://github.com/devboell/fretboard-trainer to illustrate the approach. There are more tests in the project itself. There is redux and application specific logic in there, so you'll have to figure out what is relevant to you.

// test-utils/enzyme-queries/listEditor.js
// reusable enzyme queries to mimic and check user acions
import { pick } from 'ramda'
const listButton = (index, wrapper) =>
wrapper.find('List Button').at(index)
export const pickData = pick(['id', 'name', 'type'])
export const clickListButton = (index, wrapper) =>
listButton(index, wrapper).simulate('click')
export const listButtonIsSelected = (index, wrapper) =>
listButton(index, wrapper).props().isSelected
export const changeName = (name, wrapper) =>
wrapper.find('Form input[name="name"]')
.simulate('change', { target: { value: name, name: 'name' } })
export const formIsPristine = wrapper =>
wrapper.find('Form').props().isPristine
export const saveChanges = wrapper =>
wrapper.find('Form').simulate('submit')
export const saveButtonIsDisabled = wrapper =>
wrapper.find('SaveButton button').props().disabled
export const newButtonIsDisabled = wrapper =>
wrapper.find('NewButton').props().disabled
export const previewButtonIsDisabled = wrapper =>
wrapper.find('PreviewButton').props().disabled
export const clickNew = (typeIdx, wrapper) => {
wrapper.find('NewButton').simulate('mouseenter')
wrapper.find('NewButton DropDownItem').at(typeIdx).simulate('click')
}
export const clickDelete = wrapper =>
wrapper.find('DeleteButton').simulate('click')
export const checkPanelModeId = (id, wrapper) =>
wrapper.find('Form input[name="panelModeIds"]').at(0)
.simulate('change', { target: { value: id, name: 'panelModeIds', checked: true } })
export const checkAllAnswers = wrapper =>
wrapper.find('Form input[name="allAnswers"]')
.simulate('change', { target: { value: true, name: 'allAnswers', checked: true } })
export const checkAllowIncorrect = wrapper =>
wrapper.find('Form input[name="allowIncorrect"]')
.simulate('change', { target: { value: true, name: 'allowIncorrect', checked: true } })
export const clickPreview = wrapper =>
wrapper.find('PreviewButton').simulate('click')
export const clickClosePreview = wrapper =>
wrapper.find('ExitButton').simulate('click')
// components/containers/ListEditor/mocks.js
// this sets up the TestProvider component with mocked apollo and redux data fixtures
import React from 'react'
import TestProvider from 'test-utils'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import QUIZZES from 'graphql/Quizzes'
import PANEL_MODES from 'graphql/PanelModes'
import CREATE_QUIZ from 'graphql/CreateQuiz'
import UPDATE_QUIZ from 'graphql/UpdateQuiz'
import DELETE_QUIZ from 'graphql/DeleteQuiz'
import * as quizFxt from 'fixtures/graphql/quiz'
import * as panelFxt from 'fixtures/graphql/panelMode'
import listViewerReducer, { initialState as initialListViewerState } from 'components/containers/ListViewer/reducer'
import listEditorReducer, { initialState as initialListEditorState } from 'components/containers/ListEditor/reducer'
import runnerReducer, { initialState as initialRunnerState } from 'components/containers/Runner/reducer'
import ListEditor from './index'
export const quizzes = {
request: { query: QUIZZES },
result: { data: { quizzes: quizFxt.quizzes } },
}
export const panelModes = {
request: { query: PANEL_MODES },
result: { data: { panelModes: panelFxt.panelModes } },
}
export const createQuiz = {
request: {
query: CREATE_QUIZ,
variables: quizFxt.createQuizInputValues,
},
result: { data: { createQuiz: quizFxt.createdQuiz } },
}
export const updateQuiz = {
request: {
query: UPDATE_QUIZ,
variables: quizFxt.updateQuizInputValues,
},
result: { data: { updateQuiz: quizFxt.updatedQuiz } },
}
export const deleteQuiz = {
request: {
query: DELETE_QUIZ,
variables: { id: '3' },
},
result: { data: { deleteQuiz: '3' } },
}
export const dataMocks = [
quizzes,
panelModes,
createQuiz,
updateQuiz,
deleteQuiz,
]
const initialState = {
listViewer: initialListViewerState,
listEditor: initialListEditorState,
runner: initialRunnerState,
}
export const store = createStore(
combineReducers({
listViewer: listViewerReducer,
listEditor: listEditorReducer,
runner: runnerReducer,
}),
initialState,
applyMiddleware(thunk),
)
export const getWrapper = async () => {
const wrapper = mount((
<TestProvider
store={store}
mocks={dataMocks}
>
<ListEditor />
</TestProvider>
))
// makes sure the loading is done
await new Promise(resolve => setTimeout(resolve))
wrapper.update()
return wrapper
}
// components/containers/ListEditor/__tests__/integration/selection.test.js
// example of an actual test.
import {
clickListButton,
listButtonIsSelected,
previewButtonIsDisabled,
pickData,
formIsPristine,
saveButtonIsDisabled,
} from 'test-utils/enzyme-queries/listEditor'
import * as fxt from 'fixtures/graphql/quiz'
import { getWrapper } from '../../mocks'
let wrapper
const index = 2
const selectedQuiz = fxt.quizzes[index]
beforeAll(async () => {
wrapper = await getWrapper()
clickListButton(index, wrapper)
})
describe('Select list item', () => {
it('selects an item in List', () => {
expect(listButtonIsSelected(index, wrapper)).toBe(true)
})
it('sets the buffer in Editor', () => {
const editorProps = wrapper.find('Editor').props()
expect(pickData(editorProps.buffer)).toEqual(pickData(selectedQuiz))
})
it('form is pristine', () => {
expect(formIsPristine(wrapper)).toBe(true)
})
it('Save is disabled', () => {
expect(saveButtonIsDisabled(wrapper)).toBe(true)
})
it('Preview button is enabled', () => {
expect(previewButtonIsDisabled(wrapper)).toBe(false)
})
})
// test-utils/index.js
// for convenience wrap apollo and redux providers in one Provider component
import React from 'react'
import pt from 'prop-types'
import { MockedProvider } from 'react-apollo/test-utils'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
const TestPovider = ({ store, mocks, children }) =>
<Provider store={store}>
<MockedProvider
mocks={mocks}
>
{children}
</MockedProvider>
</Provider>
TestPovider.propTypes = {
store: pt.shape({}),
mocks: pt.arrayOf(pt.shape({})),
children: pt.node.isRequired,
}
TestPovider.defaultProps = {
store: createStore((state = {}) => state),
mocks: [],
}
export default TestPovider
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment