diff options
Diffstat (limited to 'doc/development/testing_guide/frontend_testing.md')
-rw-r--r-- | doc/development/testing_guide/frontend_testing.md | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md index 314995ca9b3..236f175cee5 100644 --- a/doc/development/testing_guide/frontend_testing.md +++ b/doc/development/testing_guide/frontend_testing.md @@ -119,6 +119,50 @@ Global mocks introduce magic and can affect how modules are imported in your tes When in doubt, construct mocks in your test file using [`jest.mock()`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options), [`jest.spyOn()`](https://jestjs.io/docs/en/jest-object#jestspyonobject-methodname), etc. +### Data-driven tests + +Similar to [RSpec's parameterized tests](best_practices.md#table-based--parameterized-tests), +Jest supports data-driven tests for: + +- Individual tests using [`test.each`](https://jestjs.io/docs/en/api#testeachtable-name-fn-timeout) (aliased to `it.each`). +- Groups of tests using [`describe.each`](https://jestjs.io/docs/en/api#describeeachtable-name-fn-timeout). + +These can be useful for reducing repetition within tests. Each option can take an array of +data values or a tagged template literal. + +For example: + +```javascript +// function to test +const icon = status => status ? 'pipeline-passed' : 'pipeline-failed' +const message = status => status ? 'pipeline-passed' : 'pipeline-failed' + +// test with array block +it.each([ + [false, 'pipeline-failed'], + [true, 'pipeline-passed'] +])('icon with %s will return %s', + (status, icon) => { + expect(renderPipeline(status)).toEqual(icon) + } +); + +// test suite with tagged template literal block +describe.each` + status | icon | message + ${false} | ${'pipeline-failed'} | ${'Pipeline failed - boo-urns'} + ${true} | ${'pipeline-passed'} | ${'Pipeline succeeded - win!'} +`('pipeline component', ({ status, icon, message }) => { + it(`returns icon ${icon} with status ${status}`, () => { + expect(icon(status)).toEqual(message) + }) + + it(`returns message ${message} with status ${status}`, () => { + expect(message(status)).toEqual(message) + }) +}); +``` + ## Karma test suite GitLab uses the [Karma][karma] test runner with [Jasmine] as its test @@ -457,6 +501,39 @@ it('waits for an event', () => { }); ``` +#### Ensuring that tests are isolated + +Tests are normally architected in a pattern which requires a recurring setup and breakdown of the component under test. This is done by making use of the `beforeEach` and `afterEach` hooks. + +Example + +```javascript + let wrapper; + + beforeEach(() => { + wrapper = mount(Component); + }); + + afterEach(() => { + wrapper.destroy(); + }); +``` + +When looking at this initially you'd suspect that the component is setup before each test and then broken down afterwards, providing isolation between tests. + +This is however not entirely true as the `destroy` method does not remove everything which has been mutated on the `wrapper` object. For functional components, destroy only removes the rendered DOM elements from the document. + +In order to ensure that a clean wrapper object and DOM are being used in each test, the breakdown of the component should rather be performed as follows: + +```javascript + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); +``` + +See also the [Vue Test Utils documention on `destroy`](https://vue-test-utils.vuejs.org/api/wrapper/#destroy). + #### Migrating flaky Karma tests to Jest Some of our Karma tests are flaky because they access the properties of a shared scope. |