summaryrefslogtreecommitdiff
path: root/doc/development/testing_guide/frontend_testing.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/testing_guide/frontend_testing.md')
-rw-r--r--doc/development/testing_guide/frontend_testing.md77
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.