diff options
Diffstat (limited to 'doc/development/testing_guide/frontend_testing.md')
-rw-r--r-- | doc/development/testing_guide/frontend_testing.md | 181 |
1 files changed, 27 insertions, 154 deletions
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md index 3af806d8f57..c70d796dfec 100644 --- a/doc/development/testing_guide/frontend_testing.md +++ b/doc/development/testing_guide/frontend_testing.md @@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Frontend testing standards and style guidelines There are two types of test suites encountered while developing frontend code -at GitLab. We use Karma with Jasmine and Jest for JavaScript unit and integration testing, +at GitLab. We use Jest for JavaScript unit and integration testing, and RSpec feature tests with Capybara for e2e (end-to-end) integration testing. Unit and feature tests need to be written for all new features. @@ -28,46 +28,9 @@ If you are looking for a guide on Vue component testing, you can jump right away We use Jest to write frontend unit and integration tests. Jest tests can be found in `/spec/frontend` and `/ee/spec/frontend` in EE. -## Karma test suite - -While GitLab has switched over to [Jest](https://jestjs.io), Karma tests still exist in our -application because some of our specs require a browser and can't be easily migrated to Jest. -Those specs intend to eventually drop Karma in favor of either Jest or RSpec. You can track this migration -in the [related epic](https://gitlab.com/groups/gitlab-org/-/epics/4900). - -[Karma](http://karma-runner.github.io/) is a test runner which uses -[Jasmine](https://jasmine.github.io/) as its test framework. Jest also uses Jasmine as foundation, -that's why it's looking quite similar. - -Karma tests live in `spec/javascripts/` and `/ee/spec/javascripts` in EE. - -`app/assets/javascripts/behaviors/autosize.js` -might have a corresponding `spec/javascripts/behaviors/autosize_spec.js` file. - -Keep in mind that in a CI environment, these tests are run in a headless -browser and you don't have access to certain APIs, such as -[`Notification`](https://developer.mozilla.org/en-US/docs/Web/API/notification), -which have to be stubbed. - -### Differences to Karma - -- Jest runs in a Node.js environment, not in a browser. [An issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/26982) for running Jest tests in a browser. -- Because Jest runs in a Node.js environment, it uses [jsdom](https://github.com/jsdom/jsdom) by default. See also its [limitations](#limitations-of-jsdom) below. -- Jest does not have access to Webpack loaders or aliases. - The aliases used by Jest are defined in its [own configuration](https://gitlab.com/gitlab-org/gitlab/-/blob/master/jest.config.js). -- All calls to `setTimeout` and `setInterval` are mocked away. See also [Jest Timer Mocks](https://jestjs.io/docs/timer-mocks). -- `rewire` is not required because Jest supports mocking modules. See also [Manual Mocks](https://jestjs.io/docs/manual-mocks). -- No [context object](https://jasmine.github.io/tutorials/your_first_suite#section-The_%3Ccode%3Ethis%3C/code%3E_keyword) is passed to tests in Jest. - This means sharing `this.something` between `beforeEach()` and `it()` for example does not work. - Instead you should declare shared variables in the context that they are needed (via `const` / `let`). -- The following cause tests to fail in Jest: - - Unmocked requests. - - Unhandled Promise rejections. - - Calls to `console.warn`, including warnings from libraries like Vue. - ### Limitations of jsdom -As mentioned [above](#differences-to-karma), Jest uses jsdom instead of a browser for running tests. +Jest uses jsdom instead of a browser for running tests. This comes with a number of limitations, namely: - [No scrolling support](https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/browser/Window.js#L623-L625) @@ -387,8 +350,7 @@ Sometimes we have to test time-sensitive code. For example, recurring events tha If the application itself is waiting for some time, mock await the waiting. In Jest this is already [done by default](https://gitlab.com/gitlab-org/gitlab/-/blob/a2128edfee799e49a8732bfa235e2c5e14949c68/jest.config.js#L47) -(see also [Jest Timer Mocks](https://jestjs.io/docs/timer-mocks)). In Karma you can use the -[Jasmine mock clock](https://jasmine.github.io/api/2.9/Clock.html). +(see also [Jest Timer Mocks](https://jestjs.io/docs/timer-mocks)). ```javascript const doSomethingLater = () => { @@ -409,20 +371,6 @@ it('does something', () => { }); ``` -**in Karma:** - -```javascript -it('does something', () => { - jasmine.clock().install(); - - doSomethingLater(); - jasmine.clock().tick(4000); - - expect(something).toBe('done'); - jasmine.clock().uninstall(); -}); -``` - ### Mocking the current location in Jest NOTE: @@ -476,8 +424,7 @@ it('passes', () => { Sometimes a test needs to wait for something to happen in the application before it continues. Avoid using [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) -because it makes the reason for waiting unclear and if used within Karma with a time larger than zero it slows down our test suite. -Instead use one of the following approaches. +because it makes the reason for waiting unclear. Instead use one of the following approaches. #### Promises and Ajax calls @@ -505,19 +452,6 @@ it('waits for an Ajax call', async () => { }); ``` -**in Karma:** - -```javascript -it('waits for an Ajax call', done => { - askTheServer() - .then(() => { - expect(something).toBe('done'); - }) - .then(done) - .catch(done.fail); -}); -``` - If you are not able to register handlers to the `Promise`, for example because it is executed in a synchronous Vue life cycle hook, take a look at the [waitFor](#wait-until-axios-requests-finish) helpers or you can flush all pending `Promise`s: **in Jest:** @@ -548,22 +482,6 @@ it('renders something', () => { }); ``` -**in Karma:** - -```javascript -it('renders something', done => { - wrapper.setProps({ value: 'new value' }); - - wrapper.vm - .$nextTick() - .then(() => { - expect(wrapper.text()).toBe('new value'); - }) - .then(done) - .catch(done.fail); -}); -``` - #### Events If the application triggers an event that you need to wait for in your test, register an event handler which contains @@ -776,7 +694,7 @@ TBU ### Stubbing and Mocking -Jasmine provides stubbing and mocking capabilities. There are some subtle differences in how to use it within Karma and Jest. +Jasmine provides stubbing and mocking capabilities. There are some subtle differences in how to use it within Jest. Stubs or spies are often used synonymously. In Jest it's quite easy thanks to the `.spyOn` method. [Official docs](https://jestjs.io/docs/jest-object#jestspyonobject-methodname) @@ -835,7 +753,6 @@ For running the frontend tests, you need the following commands: - `rake frontend:fixtures` (re-)generates [fixtures](#frontend-test-fixtures). Make sure that fixtures are up-to-date before running tests that require them. - `yarn jest` runs Jest tests. -- `yarn karma` runs Karma tests. ### Live testing and focused testing -- Jest @@ -860,49 +777,36 @@ yarn jest ./path/to/folder/ yarn jest term ``` -### Live testing and focused testing -- Karma +## Frontend test fixtures -Karma allows something similar, but it's way more costly. +Frontend fixtures are files containing responses from backend controllers. These responses can be either HTML +generated from HAML templates or JSON payloads. Frontend tests that rely on these responses are +often using fixtures to validate correct integration with the backend code. -Running Karma with `yarn run karma-start` compiles the JavaScript -assets and runs a server at `http://localhost:9876/` where it automatically -runs the tests on any browser which connects to it. You can enter that URL on -multiple browsers at once to have it run the tests on each in parallel. +### Use fixtures -While Karma is running, any changes you make instantly trigger a recompile -and retest of the **entire test suite**, so you can see instantly if you've broken -a test with your changes. You can use [Jasmine focused](https://jasmine.github.io/2.5/focused_specs.html) or -excluded tests (with `fdescribe` or `xdescribe`) to get Karma to run only the -tests you want while you're working on a specific feature, but make sure to -remove these directives when you commit your code. +Jest uses `spec/frontend/__helpers__/fixtures.js` to import fixtures in tests. -It is also possible to only run Karma on specific folders or files by filtering -the run tests via the argument `--filter-spec` or short `-f`: +The following are examples of tests that work for Jest: -```shell -# Run all files -yarn karma-start -# Run specific spec files -yarn karma-start --filter-spec profile/account/components/update_username_spec.js -# Run specific spec folder -yarn karma-start --filter-spec profile/account/components/ -# Run all specs which path contain vue_shared or vie -yarn karma-start -f vue_shared -f vue_mr_widget -``` +```javascript +it('makes a request', () => { + const responseBody = getJSONFixture('some/fixture.json'); // loads spec/frontend/fixtures/some/fixture.json + axiosMock.onGet(endpoint).reply(200, responseBody); -You can also use glob syntax to match files. Remember to put quotes around the -glob otherwise your shell may split it into multiple arguments: + myButton.click(); -```shell -# Run all specs named `file_spec` within the IDE subdirectory -yarn karma -f 'spec/javascripts/ide/**/file_spec.js' -``` + // ... +}); -## Frontend test fixtures +it('uses some HTML element', () => { + loadFixtures('some/page.html'); // loads spec/frontend/fixtures/some/page.html and adds it to the DOM -Frontend fixtures are files containing responses from backend controllers. These responses can be either HTML -generated from HAML templates or JSON payloads. Frontend tests that rely on these responses are -often using fixtures to validate correct integration with the backend code. + const element = document.getElementById('#my-id'); + + // ... +}); +``` ### Generate fixtures @@ -961,34 +865,6 @@ This will create a new fixture located at You can import the JSON fixture in a Jest test using the `getJSONFixture` method [as described below](#use-fixtures). -### Use fixtures - -Jest and Karma test suites import fixtures in different ways: - -- The Karma test suite are served by [jasmine-jquery](https://github.com/velesin/jasmine-jquery). -- Jest use `spec/frontend/__helpers__/fixtures.js`. - -The following are examples of tests that work for both Karma and Jest: - -```javascript -it('makes a request', () => { - const responseBody = getJSONFixture('some/fixture.json'); // loads spec/frontend/fixtures/some/fixture.json - axiosMock.onGet(endpoint).reply(200, responseBody); - - myButton.click(); - - // ... -}); - -it('uses some HTML element', () => { - loadFixtures('some/page.html'); // loads spec/frontend/fixtures/some/page.html and adds it to the DOM - - const element = document.getElementById('#my-id'); - - // ... -}); -``` - ## Data-driven tests Similar to [RSpec's parameterized tests](best_practices.md#table-based--parameterized-tests), @@ -1139,13 +1015,10 @@ Main information on frontend testing levels can be found in the [Testing Levels Tests relevant for frontend development can be found at the following places: -- `spec/javascripts/`, for Karma tests - `spec/frontend/`, for Jest tests - `spec/features/`, for RSpec tests -RSpec runs complete [feature tests](testing_levels.md#frontend-feature-tests), while the Jest and Karma directories contain [frontend unit tests](testing_levels.md#frontend-unit-tests), [frontend component tests](testing_levels.md#frontend-component-tests), and [frontend integration tests](testing_levels.md#frontend-integration-tests). - -All tests in `spec/javascripts/` are intended to be migrated to `spec/frontend/` (see also [#52483](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52483)). +RSpec runs complete [feature tests](testing_levels.md#frontend-feature-tests), while the Jest directories contain [frontend unit tests](testing_levels.md#frontend-unit-tests), [frontend component tests](testing_levels.md#frontend-component-tests), and [frontend integration tests](testing_levels.md#frontend-integration-tests). Before May 2018, `features/` also contained feature tests run by Spinach. These tests were removed from the codebase in May 2018 ([#23036](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/23036)). |