Skip to content
Snippets Groups Projects
Commit b83a4f83 authored by Phil Hughes's avatar Phil Hughes
Browse files

Merge branch '64722-mg-export-frontend-fixtures' into 'master'

Resolve "Export frontend fixtures as pipeline artifact"

Closes #64722 and #59166

See merge request gitlab-org/gitlab-ce!30917
parents 4c30b0a1 444a3627
No related branches found
No related tags found
No related merge requests found
Showing
with 71 additions and 44 deletions
Loading
Loading
@@ -137,6 +137,7 @@ karma:
paths:
- chrome_debug.log
- coverage-javascript/
- tmp/tests/frontend/
# see https://gitlab.com/gitlab-org/gitlab-ce/issues/64756
# reports:
# junit: junit_karma.xml
Loading
Loading
@@ -151,7 +152,7 @@ jest:
script:
- scripts/gitaly-test-spawn
- date
- bundle exec rake karma:fixtures
- bundle exec rake frontend:fixtures
- date
- yarn jest --ci --coverage
artifacts:
Loading
Loading
@@ -161,6 +162,7 @@ jest:
paths:
- coverage-frontend/
- junit_jest.xml
- tmp/tests/frontend/
# see https://gitlab.com/gitlab-org/gitlab-ce/issues/64756
# reports:
# junit: junit_jest.xml
Loading
Loading
Loading
Loading
@@ -60,8 +60,8 @@ Style/FrozenStringLiteralComment:
RSpec/FilePath:
Exclude:
- 'qa/**/*'
- 'spec/javascripts/fixtures/*'
- 'ee/spec/javascripts/fixtures/*'
- 'spec/frontend/fixtures/*'
- 'ee/spec/frontend/fixtures/*'
- 'spec/requests/api/v3/*'
 
Naming/FileName:
Loading
Loading
Loading
Loading
@@ -107,7 +107,8 @@ if (specFilters.length) {
module.exports = function(config) {
process.env.TZ = 'Etc/UTC';
 
const fixturesPath = `${IS_EE ? 'ee/' : ''}spec/javascripts/fixtures`;
const fixturesPath = `tmp/tests/frontend/fixtures${IS_EE ? '-ee' : ''}`;
const staticFixturesPath = 'spec/frontend/fixtures/static';
 
const karmaConfig = {
basePath: ROOT_PATH,
Loading
Loading
@@ -131,8 +132,13 @@ module.exports = function(config) {
frameworks: ['jasmine'],
files: [
{ pattern: 'spec/javascripts/test_bundle.js', watched: false },
{ pattern: `${fixturesPath}/**/*@(.json|.html|.png|.bmpr|.pdf)`, included: false },
{ pattern: `${fixturesPath}/**/*`, included: false },
{ pattern: `${staticFixturesPath}/**/*`, included: false },
],
proxies: {
'/fixtures/': `/base/${fixturesPath}/`,
'/fixtures/static/': `/base/${staticFixturesPath}/`,
},
preprocessors: {
'spec/javascripts/**/*.js': ['webpack', 'sourcemap'],
'ee/spec/javascripts/**/*.js': ['webpack', 'sourcemap'],
Loading
Loading
Loading
Loading
@@ -80,18 +80,20 @@ describe('Component', () => {
Remember that the performance of each test depends on the environment.
 
### Manual module mocks
Jest supports [manual module mocks](https://jestjs.io/docs/en/manual-mocks) by placing a mock in a `__mocks__/` directory next to the source module. **Don't do this.** We want to keep all of our test-related code in one place (the `spec/` folder), and the logic that Jest uses to apply mocks from `__mocks__/` is rather inconsistent.
 
Instead, our test runner detects manual mocks from `spec/frontend/mocks/`. Any mock placed here is automatically picked up and injected whenever you import its source module.
 
- Files in `spec/frontend/mocks/ce` will mock the corresponding CE module from `app/assets/javascripts`, mirroring the source module's path.
- Example: `spec/frontend/mocks/ce/lib/utils/axios_utils` will mock the module `~/lib/utils/axios_utils`.
- Example: `spec/frontend/mocks/ce/lib/utils/axios_utils` will mock the module `~/lib/utils/axios_utils`.
- Files in `spec/frontend/mocks/node` will mock NPM packages of the same name or path.
- We don't support mocking EE modules yet.
 
If a mock is found for which a source module doesn't exist, the test suite will fail. 'Virtual' mocks, or mocks that don't have a 1-to-1 association with a source module, are not supported yet.
 
#### Writing a mock
Create a JS module in the appropriate place in `spec/frontend/mocks/`. That's it. It will automatically mock its source package in all tests.
 
Make sure that your mock's export has the same format as the mocked module. So, if you're mocking a CommonJS module, you'll need to use `module.exports` instead of the ES6 `export`.
Loading
Loading
@@ -99,14 +101,15 @@ Make sure that your mock's export has the same format as the mocked module. So,
It might be useful for a mock to expose a property that indicates if the mock was loaded. This way, tests can assert the presence of a mock without calling any logic and causing side-effects. The `~/lib/utils/axios_utils` module mock has such a property, `isMock`, that is `true` in the mock and undefined in the original class. Jest's mock functions also have a `mock` property that you can test.
 
#### Bypassing mocks
If you ever need to import the original module in your tests, use [`jest.requireActual()`](https://jestjs.io/docs/en/jest-object#jestrequireactualmodulename) (or `jest.requireActual().default` for the default export). The `jest.mock()` and `jest.unmock()` won't have an effect on modules that have a manual mock, because mocks are imported and cached before any tests are run.
 
#### Keep mocks light
Global mocks introduce magic and can affect how modules are imported in your tests. Try to keep them as light as possible and dependency-free. A global mock should be useful for any unit test. For example, the `axios_utils` and `jquery` module mocks throw an error when an HTTP request is attempted, since this is useful behaviour in >99% of tests.
 
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.
 
## Karma test suite
 
GitLab uses the [Karma][karma] test runner with [Jasmine] as its test
Loading
Loading
@@ -462,7 +465,7 @@ See this [section][vue-test].
 
For running the frontend tests, you need the following commands:
 
- `rake karma:fixtures` (re-)generates [fixtures](#frontend-test-fixtures).
- `rake frontend:fixtures` (re-)generates [fixtures](#frontend-test-fixtures).
- `yarn test` executes the tests.
 
As long as the fixtures don't change, `yarn test` is sufficient (and saves you some time).
Loading
Loading
@@ -515,8 +518,8 @@ Information on setting up and running RSpec integration tests with
Code that is added to HAML templates (in `app/views/`) or makes Ajax requests to the backend has tests that require HTML or JSON from the backend.
Fixtures for these tests are located at:
 
- `spec/javascripts/fixtures/`, for running tests in CE.
- `ee/spec/javascripts/fixtures/`, for running tests in EE.
- `spec/frontend/fixtures/`, for running tests in CE.
- `ee/spec/frontend/fixtures/`, for running tests in EE.
 
Fixture files in:
 
Loading
Loading
@@ -527,7 +530,7 @@ 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/javascripts/fixtures/some/fixture.json
const responseBody = getJSONFixture('some/fixture.json'); // loads spec/frontend/fixtures/some/fixture.json
axiosMock.onGet(endpoint).reply(200, responseBody);
 
myButton.click();
Loading
Loading
@@ -536,7 +539,7 @@ it('makes a request', () => {
});
 
it('uses some HTML element', () => {
loadFixtures('some/page.html'); // loads spec/javascripts/fixtures/some/page.html and adds it to the DOM
loadFixtures('some/page.html'); // loads spec/frontend/fixtures/some/page.html and adds it to the DOM
 
const element = document.getElementById('#my-id');
 
Loading
Loading
@@ -544,12 +547,12 @@ it('uses some HTML element', () => {
});
```
 
HTML and JSON fixtures are generated from backend views and controllers using RSpec (see `spec/javascripts/fixtures/*.rb`).
HTML and JSON fixtures are generated from backend views and controllers using RSpec (see `spec/frontend/fixtures/*.rb`).
 
For each fixture, the content of the `response` variable is stored in the output file.
This variable gets automagically set if the test is marked as `type: :request` or `type: :controller`.
Fixtures are regenerated using the `bin/rake karma:fixtures` command but you can also generate them individually,
for example `bin/rspec spec/javascripts/fixtures/merge_requests.rb`.
Fixtures are regenerated using the `bin/rake frontend:fixtures` command but you can also generate them individually,
for example `bin/rspec spec/frontend/fixtures/merge_requests.rb`.
When creating a new fixture, it often makes sense to take a look at the corresponding tests for the endpoint in `(ee/)spec/controllers/` or `(ee/)spec/requests/`.
 
## Gotchas
Loading
Loading
unless Rails.env.production?
namespace :frontend do
desc 'GitLab | Frontend | Generate fixtures for JavaScript tests'
RSpec::Core::RakeTask.new(:fixtures, [:pattern]) do |t, args|
args.with_defaults(pattern: '{spec,ee/spec}/frontend/fixtures/*.rb')
ENV['NO_KNAPSACK'] = 'true'
t.pattern = args[:pattern]
t.rspec_opts = '--format documentation'
end
desc 'GitLab | Frontend | Run JavaScript tests'
task tests: ['yarn:check'] do
sh "yarn test" do |ok, res|
abort('rake frontend:tests failed') unless ok
end
end
end
desc 'GitLab | Frontend | Shortcut for frontend:fixtures and frontend:tests'
task frontend: ['frontend:fixtures', 'frontend:tests']
end
unless Rails.env.production?
namespace :karma do
# alias exists for legacy reasons
desc 'GitLab | Karma | Generate fixtures for JavaScript tests'
task fixtures: ['karma:rspec_fixtures']
desc 'GitLab | Karma | Generate fixtures using RSpec'
RSpec::Core::RakeTask.new(:rspec_fixtures, [:pattern]) do |t, args|
args.with_defaults(pattern: '{spec,ee/spec}/javascripts/fixtures/*.rb')
ENV['NO_KNAPSACK'] = 'true'
t.pattern = args[:pattern]
t.rspec_opts = '--format documentation'
end
task fixtures: ['frontend:fixtures']
 
desc 'GitLab | Karma | Run JavaScript tests'
task tests: ['yarn:check'] do
Loading
Loading
/* eslint-disable import/no-commonjs */
 
const path = require('path');
const { ErrorWithStack } = require('jest-util');
const JSDOMEnvironment = require('jest-environment-jsdom');
 
const ROOT_PATH = path.resolve(__dirname, '../..');
class CustomEnvironment extends JSDOMEnvironment {
constructor(config, context) {
super(config, context);
Loading
Loading
@@ -35,9 +38,8 @@ class CustomEnvironment extends JSDOMEnvironment {
this.rejectedPromises.push(error);
};
 
this.global.fixturesBasePath = `${process.cwd()}/${
IS_EE ? 'ee/' : ''
}spec/javascripts/fixtures`;
this.global.fixturesBasePath = `${ROOT_PATH}/tmp/tests/frontend/fixtures${IS_EE ? '-ee' : ''}`;
this.global.staticFixturesBasePath = `${ROOT_PATH}/spec/frontend/fixtures`;
 
// Not yet supported by JSDOM: https://github.com/jsdom/jsdom/issues/317
this.global.document.createRange = () => ({
Loading
Loading
Loading
Loading
@@ -21,6 +21,6 @@ describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :controll
it 'abuse_reports/abuse_reports_list.html' do
get :index
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -23,6 +23,6 @@ describe Admin::UsersController, '(JavaScript fixtures)', type: :controller do
 
get :new
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -28,6 +28,6 @@ describe Admin::ApplicationSettingsController, '(JavaScript fixtures)', type: :c
 
get :show
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -34,6 +34,6 @@ describe Projects::AutocompleteSourcesController, '(JavaScript fixtures)', type:
type_id: issue.id
}
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -29,6 +29,6 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do
id: 'add-ipython-files/files/ipython/basic.ipynb'
})
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -23,6 +23,6 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller
project_id: project
})
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -27,6 +27,6 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle
project_id: project
}
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -29,6 +29,6 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle
id: cluster
}
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -28,6 +28,6 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller
 
get :show, params: params
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -38,6 +38,6 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control
project_id: project
}, format: :json
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -21,7 +21,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do
it 'groups/edit.html' do
get :edit, params: { id: group }
 
expect(response).to be_success
expect(response).to be_successful
end
end
 
Loading
Loading
@@ -29,7 +29,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do
it 'groups/ci_cd_settings.html' do
get :show, params: { group_id: group }
 
expect(response).to be_success
expect(response).to be_successful
end
end
end
Loading
Loading
@@ -48,7 +48,7 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller
project_id: project
}
 
expect(response).to be_success
expect(response).to be_successful
end
 
private
Loading
Loading
@@ -60,7 +60,7 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller
id: issue.to_param
}
 
expect(response).to be_success
expect(response).to be_successful
end
end
 
Loading
Loading
@@ -117,6 +117,6 @@ describe API::Issues, '(JavaScript fixtures)', type: :request do
 
get_related_merge_requests(project.id, issue.iid, user)
 
expect(response).to be_success
expect(response).to be_successful
end
end
Loading
Loading
@@ -39,7 +39,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do
id: build_with_artifacts.to_param
}
 
expect(response).to be_success
expect(response).to be_successful
end
 
it 'jobs/delayed.json' do
Loading
Loading
@@ -49,6 +49,6 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do
id: delayed_job.to_param
}, format: :json
 
expect(response).to be_success
expect(response).to be_successful
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment