Commit c1657d26 authored by Marcia Ramos's avatar Marcia Ramos

Merge branch '257814-add-test-and-docs-for-extendedwrapper-utility' into 'master'

Add tests and docs for extendedWrapper util

See merge request gitlab-org/gitlab!47671
parents 15ee22ee 19d498ed
......@@ -204,6 +204,7 @@ possible selectors include:
- A semantic attribute like `name` (also verifies that `name` was setup properly)
- A `data-testid` attribute ([recommended by maintainers of `@vue/test-utils`](https://github.com/vuejs/vue-test-utils/issues/1498#issuecomment-610133465))
optionally combined with [`findByTestId`](#extendedwrapper-and-findbytestid)
- a Vue `ref` (if using `@vue/test-utils`)
```javascript
......@@ -220,9 +221,10 @@ it('exists', () => {
// Good (especially for unit tests)
wrapper.find(FooComponent);
wrapper.find('input[name=foo]');
wrapper.find('[data-testid="foo"]');
wrapper.find('[data-testid="my-foo-id"]');
wrapper.findByTestId('my-foo-id'); // with the extendedWrapper utility – check below
wrapper.find({ ref: 'foo'});
// Bad
wrapper.find('.js-foo');
wrapper.find('.btn-primary');
......@@ -231,6 +233,8 @@ it('exists', () => {
});
```
It is recommended to use `kebab-case` for `data-testid` attribute.
It is not recommended that you add `.js-*` classes just for testing purposes. Only do this if there are no other feasible options available.
Do not use a `.qa-*` class or `data-qa-selector` attribute for any tests other than QA end-to-end testing.
......@@ -1041,7 +1045,7 @@ testAction(
);
```
Check an example in [`spec/javascripts/ide/stores/actions_spec.jsspec/javascripts/ide/stores/actions_spec.js`](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/javascripts/ide/stores/actions_spec.js).
Check an example in [`spec/frontend/ide/stores/actions_spec.js`](https://gitlab.com/gitlab-org/gitlab/-/blob/fdc7197609dfa7caeb1d962042a26248e49f27da/spec/frontend/ide/stores/actions_spec.js#L392).
### Wait until Axios requests finish
......@@ -1053,6 +1057,29 @@ These are very useful if you don't have a handle to the request's Promise, for e
Both functions run `callback` on the next tick after the requests finish (using `setImmediate()`), to allow any `.then()` or `.catch()` handlers to run.
### `extendedWrapper` and `findByTestId`
Using `data-testid` is one of the [recommended ways to query DOM elements](#how-to-query-dom-elements).
You can use the `extendedWrapper` utility on the `wrapper` returned by `shalowMount`/`mount`.
By doing so, the `wrapper` provides you with the ability to perform a `findByTestId`,
which is a shortcut to the more verbose `wrapper.find('[data-testid="my-test-id"]');`
```javascript
import { extendedWrapper } from 'jest/helpers/vue_test_utils_helper';
describe('FooComponent', () => {
const wrapper = extendedWrapper(shallowMount({
template: `<div data-testid="my-test-id"></div>`,
}));
it('exists', () => {
expect(wrapper.findByTestId('my-test-id').exists()).toBe(true);
});
});
```
Check an example in [`spec/frontend/alert_management/components/alert_details_spec.js`](https://gitlab.com/gitlab-org/gitlab/-/blob/ac1c9fa4c5b3b45f9566147b1c88fd1339cd7c25/spec/frontend/alert_management/components/alert_details_spec.js#L32).
## Testing with older browsers
Some regressions only affect a specific browser version. We can install and test in particular browsers with either Firefox or BrowserStack using the following steps:
......
import { isArray } from 'lodash';
const vNodeContainsText = (vnode, text) =>
(vnode.text && vnode.text.includes(text)) ||
(vnode.children && vnode.children.filter(child => vNodeContainsText(child, text)).length);
......@@ -34,9 +36,18 @@ export const waitForMutation = (store, expectedMutationType) =>
});
});
export const extendedWrapper = wrapper =>
Object.defineProperty(wrapper, 'findByTestId', {
export const extendedWrapper = wrapper => {
if (isArray(wrapper) || !wrapper?.find) {
// eslint-disable-next-line no-console
console.warn(
'[vue-test-utils-helper]: you are trying to extend an object that is not a VueWrapper.',
);
return wrapper;
}
return Object.defineProperty(wrapper, 'findByTestId', {
value(id) {
return this.find(`[data-testid="${id}"]`);
},
});
};
import { shallowMount } from '@vue/test-utils';
import { shallowWrapperContainsSlotText } from './vue_test_utils_helper';
import { extendedWrapper, shallowWrapperContainsSlotText } from './vue_test_utils_helper';
describe('Vue test utils helpers', () => {
describe('shallowWrapperContainsSlotText', () => {
......@@ -45,4 +45,48 @@ describe('Vue test utils helpers', () => {
expect(shallowWrapperContainsSlotText(mockComponent, 'namedSlot', searchText)).toBe(false);
});
});
describe('extendedWrapper', () => {
describe('when an invalid wrapper is provided', () => {
beforeEach(() => {
// eslint-disable-next-line no-console
console.warn = jest.fn();
});
it.each`
wrapper
${{}}
${[]}
${null}
${undefined}
${1}
${''}
`('should warn with an error when the wrapper is $wrapper', ({ wrapper }) => {
extendedWrapper(wrapper);
/* eslint-disable no-console */
expect(console.warn).toHaveBeenCalled();
expect(console.warn).toHaveBeenCalledWith(
'[vue-test-utils-helper]: you are trying to extend an object that is not a VueWrapper.',
);
/* eslint-enable no-console */
});
});
describe('findByTestId', () => {
const testId = 'a-component';
let mockComponent;
beforeEach(() => {
mockComponent = extendedWrapper(
shallowMount({
template: `<div data-testid="${testId}"></div>`,
}),
);
});
it('should find the component by test id', () => {
expect(mockComponent.findByTestId(testId).exists()).toBe(true);
});
});
});
});
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