Driver Pattern
A project for generating react test drivers.
Features:
- Automatic react component property setters
- Automatic redux state setters
- Easily declare getters
- Easily declare actions (including async actions)
- Define the driver once in the top of the test suite and initialize it between tests
- Default component property and state property initializers (initialized for each test)
Resources:
BDD feat. Driver & Builder Patterns
Usage
You can see usage examples in the test file, those are some cherry-picked exmaples:
Givens & Getters
Automatically created "givens" based on properties & declared getters:
const NameComponent: FC<ComponentProps> = ({ name }: { name: string }) => (
<span data-testid="test-name">{name}</span>
);
const driver = createDriver(NameComponent, {
getters: {
name: "test-name",
},
});
driver.given.name("Some Name").when.render();
expect(driver.get.name()!.innerHTML).toEqual("Some Name");
Actions
Actions are defined as a function which receives a get parameter, giving you access to the the get object infered from getters.
Simply put, you can use driver.get.someGetter()
when performing actions:
When defining actions, you can then use the .on
property to trigger them:
const driver = createDriver(Component, {
getters: {
button: "test-button",
},
actions: get => ({
click: () => fireEvent.click(driver.get.button()!),
}),
});
const onClickSpy = jest.fn();
driver.given.onClick(onClickSpy).when.render().on.click();
expect(onClickSpy).toHaveBeenCalledTimes(1);
Async Actions
const driver = createDriver(Component, {
getters: {
button: "test-button",
},
actions: get => ({
click: () => {
fireEvent.click(driver.get.button()!);
return waitFor();
},
}),
});
await driver.given.onClick(onClickSpy).when.render().on.click();
expect();
Default Props
const name = chance.word();
const driver = createDriver(Component, {
defaultProps: () => ({ name }),
getters: {
name: "test-name",
},
});
driver.when.render();
expect(driver.get.name()!.innerHTML).toEqual(name);
Supprt for redux state
Receives a createStore method, which:
- returns a redux Store (enabling to infer the store state)
- receives a preloadedState state, enabling the driver to inject an initial state
const createStore = ({ preloadedState }: { preloadedState: any }) => configureStore(...);
const driver = createDriver(ReduxComponent, {
getters: {
title: "test-redux-title",
},
createStore,
});
driver.givenState.title("Some Title").when.render();
expect(driver.get.title()!.innerHTML).toEqual("Some Title");
Default State
it("should get default state from defaultState", () => {
const title = chance.word();
const driver = createDriver(ReduxComponent, {
getters: {
title: "test-redux-title",
},
createStore,
defaultState: () => ({ title }),
});
driver.when.render();
expect(driver.get.title()!.innerHTML).toEqual(title);
});
Initialize
You can call initialize to empty props & state between tests (or initialize then to defaultProps & defaultState)
describe("test suite", () => {
const driver = createDriver(Component, {
getters: {
propRender: "some-component-prop",
stateRender: "some-state-prop",
},
defaultProps: () => ({
someComponentProp: chance.string()
}),
createStore,
defaultProps: () => ({
someStateProp: chance.string()
}),
});
beforeEach(() => driver.initialize());
it("test 1", () => {
});
it("test 2", () => {
});
});