Commit 78d15274 authored by Jacques Erasmus's avatar Jacques Erasmus

Merge branch 'justin_ho-update-testing-style-guide-with-new-extended-wrappers' into 'master'

Update docs with newest recommendations on writing specs

See merge request gitlab-org/gitlab!62996
parents 1870bd83 45afaa38
...@@ -1097,7 +1097,7 @@ it('renders a loading state', () => { ...@@ -1097,7 +1097,7 @@ it('renders a loading state', () => {
const mockApollo = createMockApolloProvider(); const mockApollo = createMockApolloProvider();
const wrapper = createComponent({ mockApollo }); const wrapper = createComponent({ mockApollo });
expect(wrapper.find(LoadingSpinner).exists()).toBe(true) expect(wrapper.findComponent(LoadingSpinner).exists()).toBe(true)
}); });
it('renders designs list', async () => { it('renders designs list', async () => {
...@@ -1399,7 +1399,6 @@ describe('My Index test with `createMockApollo`', () => { ...@@ -1399,7 +1399,6 @@ describe('My Index test with `createMockApollo`', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
fetchLocalUserSpy = null; fetchLocalUserSpy = null;
}); });
......
...@@ -463,7 +463,7 @@ Creating a global, mutable wrapper provides a number of advantages, including th ...@@ -463,7 +463,7 @@ Creating a global, mutable wrapper provides a number of advantages, including th
let wrapper; let wrapper;
// this can now be reused across tests // this can now be reused across tests
const findMyComponent = wrapper.find(MyComponent); const findMyComponent = wrapper.findComponent(MyComponent);
// ... // ...
}) })
``` ```
...@@ -565,16 +565,15 @@ the mounting function (`mount` or `shallowMount`) to be used to mount the compon ...@@ -565,16 +565,15 @@ the mounting function (`mount` or `shallowMount`) to be used to mount the compon
function createComponent({ mountFn = shallowMount } = {}) { } function createComponent({ mountFn = shallowMount } = {}) { }
``` ```
1. Wrap calls to `mount` and `shallowMount` in `extendedWrapper`, this exposes `wrapper.findByTestId()`: 1. Use the `mountExtended` and `shallowMountExtended` helpers to expose `wrapper.findByTestId()`:
```javascript ```javascript
import { shallowMount } from '@vue/test-utils'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { SomeComponent } from 'components/some_component.vue'; import { SomeComponent } from 'components/some_component.vue';
let wrapper; let wrapper;
const createWrapper = () => { wrapper = extendedWrapper(shallowMount(SomeComponent)); }; const createWrapper = () => { wrapper = shallowMountExtended(SomeComponent); };
const someButton = () => wrapper.findByTestId('someButtonTestId'); const someButton = () => wrapper.findByTestId('someButtonTestId');
``` ```
......
...@@ -27,15 +27,15 @@ See [this video](https://youtu.be/-BkEhghP-kM) for an in-depth overview and inve ...@@ -27,15 +27,15 @@ See [this video](https://youtu.be/-BkEhghP-kM) for an in-depth overview and inve
**Remedy - Try cloning the object that has Vue watchers** **Remedy - Try cloning the object that has Vue watchers**
```patch ```patch
- expect(wrapper.find(ChildComponent).props()).toEqual(...); - expect(wrapper.findComponent(ChildComponent).props()).toEqual(...);
+ expect(cloneDeep(wrapper.find(ChildComponent).props())).toEqual(...) + expect(cloneDeep(wrapper.findComponent(ChildComponent).props())).toEqual(...)
``` ```
**Remedy - Try using `toMatchObject` instead of `toEqual`** **Remedy - Try using `toMatchObject` instead of `toEqual`**
```patch ```patch
- expect(wrapper.find(ChildComponent).props()).toEqual(...); - expect(wrapper.findComponent(ChildComponent).props()).toEqual(...);
+ expect(wrapper.find(ChildComponent).props()).toMatchObject(...); + expect(wrapper.findComponent(ChildComponent).props()).toMatchObject(...);
``` ```
Please note that `toMatchObject` actually changes the nature of the assertion and won't fail if some items are **missing** from the expectation. Please note that `toMatchObject` actually changes the nature of the assertion and won't fail if some items are **missing** from the expectation.
......
...@@ -323,17 +323,13 @@ testing the rendered output. ...@@ -323,17 +323,13 @@ testing the rendered output.
Here's an example of a well structured unit test for [this Vue component](#appendix---vue-component-subject-under-test): Here's an example of a well structured unit test for [this Vue component](#appendix---vue-component-subject-under-test):
```javascript ```javascript
import { shallowMount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import App from '~/todos/app.vue'; import App from '~/todos/app.vue';
const TEST_TODOS = [ const TEST_TODOS = [{ text: 'Lorem ipsum test text' }, { text: 'Lorem ipsum 2' }];
{ text: 'Lorem ipsum test text' },
{ text: 'Lorem ipsum 2' },
];
const TEST_NEW_TODO = 'New todo title'; const TEST_NEW_TODO = 'New todo title';
const TEST_TODO_PATH = '/todos'; const TEST_TODO_PATH = '/todos';
...@@ -351,28 +347,27 @@ describe('~/todos/app.vue', () => { ...@@ -351,28 +347,27 @@ describe('~/todos/app.vue', () => {
afterEach(() => { afterEach(() => {
// IMPORTANT: Clean up the component instance and axios mock adapter // IMPORTANT: Clean up the component instance and axios mock adapter
wrapper.destroy(); wrapper.destroy();
wrapper = null;
mock.restore(); mock.restore();
}); });
// It is very helpful to separate setting up the component from // It is very helpful to separate setting up the component from
// its collaborators (for example, Vuex and axios). // its collaborators (for example, Vuex and axios).
const createWrapper = (props = {}) => { const createWrapper = (props = {}) => {
wrapper = extendedWrapper( wrapper = shallowMountExtended(App, {
shallowMount(App, {
propsData: { propsData: {
path: TEST_TODO_PATH, path: TEST_TODO_PATH,
...props, ...props,
}, },
}) });
);
}; };
// Helper methods greatly help test maintainability and readability. // Helper methods greatly help test maintainability and readability.
const findLoader = () => wrapper.find(GlLoadingIcon); const findLoader = () => wrapper.findComponent(GlLoadingIcon);
const findAddButton = () => wrapper.findByTestId('add-button'); const findAddButton = () => wrapper.findByTestId('add-button');
const findTextInput = () => wrapper.findByTestId('text-input'); const findTextInput = () => wrapper.findByTestId('text-input');
const findTodoData = () => wrapper.findAll('[data-testid="todo-item"]').wrappers.map(wrapper => ({ text: wrapper.text() })); const findTodoData = () =>
wrapper
.findAllByTestId('todo-item')
.wrappers.map((item) => ({ text: item.text() }));
describe('when mounted and loading', () => { describe('when mounted and loading', () => {
beforeEach(() => { beforeEach(() => {
...@@ -401,14 +396,13 @@ describe('~/todos/app.vue', () => { ...@@ -401,14 +396,13 @@ describe('~/todos/app.vue', () => {
expect(findTodoData()).toEqual(TEST_TODOS); expect(findTodoData()).toEqual(TEST_TODOS);
}); });
it('when todo is added, should post new todo', () => { it('when todo is added, should post new todo', async () => {
findTextInput().vm.$emit('update', TEST_NEW_TODO) findTextInput().vm.$emit('update', TEST_NEW_TODO);
findAddButton().vm.$emit('click'); findAddButton().vm.$emit('click');
return wrapper.vm.$nextTick() await wrapper.vm.$nextTick();
.then(() => {
expect(mock.history.post.map(x => JSON.parse(x.data))).toEqual([{ text: TEST_NEW_TODO }]); expect(mock.history.post.map((x) => JSON.parse(x.data))).toEqual([{ text: TEST_NEW_TODO }]);
});
}); });
}); });
}); });
......
...@@ -464,7 +464,6 @@ describe('component', () => { ...@@ -464,7 +464,6 @@ describe('component', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
it('should show a user', async () => { it('should show a user', async () => {
......
...@@ -249,7 +249,7 @@ it('exists', () => { ...@@ -249,7 +249,7 @@ it('exists', () => {
wrapper.findByText(/Click Me/i) wrapper.findByText(/Click Me/i)
// Good (especially for unit tests) // Good (especially for unit tests)
wrapper.find(FooComponent); wrapper.findComponent(FooComponent);
wrapper.find('input[name=foo]'); wrapper.find('input[name=foo]');
wrapper.find('[data-testid="my-foo-id"]'); wrapper.find('[data-testid="my-foo-id"]');
wrapper.findByTestId('my-foo-id'); // with shallowMountExtended or mountExtended – check below wrapper.findByTestId('my-foo-id'); // with shallowMountExtended or mountExtended – check below
...@@ -281,7 +281,7 @@ Example: ...@@ -281,7 +281,7 @@ Example:
```javascript ```javascript
it('exists', () => { it('exists', () => {
wrapper.find(FooComponent); wrapper.findComponent(FooComponent);
}); });
``` ```
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment