diff options
66 files changed, 447 insertions, 223 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index 3dd1adb5f63..2be35efe1da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -272,7 +272,7 @@ GEM ruby-progressbar (~> 1.4) gemojione (3.3.0) json - get_process_mem (0.2.0) + get_process_mem (0.2.3) gettext (3.2.9) locale (>= 2.0.5) text (>= 1.3.0) diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index b503c746801..213d5c6521a 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -147,7 +147,7 @@ function deferredInitialisation() { const canaryBadge = document.querySelector('.js-canary-badge'); const canaryLink = document.querySelector('.js-canary-link'); if (canaryBadge) { - canaryBadge.classList.remove('hidden'); + canaryBadge.classList.add('hidden'); } if (canaryLink) { canaryLink.classList.add('hidden'); diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index ebf28dc842c..7b4832b84a8 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -265,6 +265,7 @@ class JiraService < IssueTrackerService def find_remote_link(issue, url) links = jira_request { issue.remotelink.all } + return unless links links.find { |link| link.object["url"] == url } end diff --git a/app/services/projects/after_import_service.rb b/app/services/projects/after_import_service.rb index afb9048e87b..bbdde4408d2 100644 --- a/app/services/projects/after_import_service.rb +++ b/app/services/projects/after_import_service.rb @@ -9,7 +9,7 @@ module Projects end def execute - Projects::HousekeepingService.new(@project, :gc).execute do + Projects::HousekeepingService.new(@project).execute do repository.delete_all_refs_except(RESERVED_REF_PREFIXES) end rescue Projects::HousekeepingService::LeaseTaken => e diff --git a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb index 05974948505..9b72480d18b 100644 --- a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb +++ b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb @@ -37,7 +37,17 @@ module Projects raise DownloadLinksError, response.message unless response.success? - parse_response_links(response['objects']) + # Since the LFS Batch API may return a Content-Ttpe of + # application/vnd.git-lfs+json + # (https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md#requests), + # HTTParty does not know this is actually JSON. + data = JSON.parse(response.body) + + raise DownloadLinksError, "LFS Batch API did return any objects" unless data.is_a?(Hash) && data.key?('objects') + + parse_response_links(data['objects']) + rescue JSON::ParserError + raise DownloadLinksError, "LFS Batch API response is not JSON" end def parse_response_links(objects_response) diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 91c51d5e091..0e15f581ddc 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -10,7 +10,7 @@ .branch-info .branch-title = sprite_icon('fork', size: 12) - = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name prepend-left-8' do + = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name prepend-left-8 qa-branch-name' do = branch.name - if branch.name == @repository.root_ref %span.badge.badge-primary.prepend-left-5 default diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 2e5747121b6..2db1f67a793 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -53,7 +53,7 @@ = time_ago_with_tooltip(member.created_at) - if show_roles - current_resource = @project || @group - .controls.member-controls.row + .controls.member-controls - if show_controls && member.source == current_resource - if member.can_resend_invite? diff --git a/changelogs/unreleased/60180-jira-service-fix-nil-on-find-call.yml b/changelogs/unreleased/60180-jira-service-fix-nil-on-find-call.yml new file mode 100644 index 00000000000..6891a9ca83c --- /dev/null +++ b/changelogs/unreleased/60180-jira-service-fix-nil-on-find-call.yml @@ -0,0 +1,5 @@ +--- +title: 'Resolved JIRA service: NoMethodError: undefined method ''find'' for nil:NilClass' +merge_request: 28206 +author: +type: fixed diff --git a/changelogs/unreleased/61550-next-badge.yml b/changelogs/unreleased/61550-next-badge.yml new file mode 100644 index 00000000000..122e394a68c --- /dev/null +++ b/changelogs/unreleased/61550-next-badge.yml @@ -0,0 +1,5 @@ +--- +title: Fixes next badge being always visible +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/61606-support-string-piwik-website-ids.yml b/changelogs/unreleased/61606-support-string-piwik-website-ids.yml new file mode 100644 index 00000000000..5c525294132 --- /dev/null +++ b/changelogs/unreleased/61606-support-string-piwik-website-ids.yml @@ -0,0 +1,5 @@ +--- +title: "Supports Matomo/Piwik string website ID (\"Protect Track ID\" plugin)" +merge_request: 28214 +author: DUVERGIER Claude +type: fixed
\ No newline at end of file diff --git a/changelogs/unreleased/ce-11542-remove-non-semantic-use-of-row-in-member-listing-controls.yml b/changelogs/unreleased/ce-11542-remove-non-semantic-use-of-row-in-member-listing-controls.yml new file mode 100644 index 00000000000..c2dcd309abd --- /dev/null +++ b/changelogs/unreleased/ce-11542-remove-non-semantic-use-of-row-in-member-listing-controls.yml @@ -0,0 +1,5 @@ +--- +title: Remove non-semantic use of `.row` in member listing controls +merge_request: 28204 +author: +type: fixed diff --git a/changelogs/unreleased/include-ee-fixtures.yml b/changelogs/unreleased/include-ee-fixtures.yml new file mode 100644 index 00000000000..ba500d92de3 --- /dev/null +++ b/changelogs/unreleased/include-ee-fixtures.yml @@ -0,0 +1,5 @@ +--- +title: Add EE fixtures to SeedFu list +merge_request: 28241 +author: +type: other diff --git a/changelogs/unreleased/sh-fix-lfs-download-errors.yml b/changelogs/unreleased/sh-fix-lfs-download-errors.yml new file mode 100644 index 00000000000..ad67df6bb06 --- /dev/null +++ b/changelogs/unreleased/sh-fix-lfs-download-errors.yml @@ -0,0 +1,5 @@ +--- +title: Properly handle LFS Batch API response in project import +merge_request: 28223 +author: +type: fixed diff --git a/changelogs/unreleased/sh-update-process-mem.yml b/changelogs/unreleased/sh-update-process-mem.yml new file mode 100644 index 00000000000..51b22fb0f00 --- /dev/null +++ b/changelogs/unreleased/sh-update-process-mem.yml @@ -0,0 +1,5 @@ +--- +title: Update get_process_mem to 0.2.3 +merge_request: 28248 +author: +type: other diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index bff809b7661..23377b43f78 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -245,7 +245,7 @@ production: &base host: example.com port: 80 # Set to 443 if you serve the pages with HTTPS https: false # Set to true if you serve the pages with HTTPS - artifacts_server: true + artifacts_server: true # Set to false if you want to disable online view of HTML artifacts # external_http: ["1.1.1.1:80", "[2001::1]:80"] # If defined, enables custom domain support in GitLab Pages # external_https: ["1.1.1.1:443", "[2001::1]:443"] # If defined, enables custom domain and certificate support in GitLab Pages admin: diff --git a/config/initializers/01_secret_token.rb b/config/initializers/01_secret_token.rb index 4328ca509ba..e24b5cbd510 100644 --- a/config/initializers/01_secret_token.rb +++ b/config/initializers/01_secret_token.rb @@ -1,3 +1,14 @@ +# WARNING: If you add a new secret to this file, make sure you also +# update Omnibus GitLab or updates will fail. Omnibus is responsible for +# writing the `secrets.yml` file. If Omnibus doesn't know about a +# secret, Rails will attempt to write to the file, but this will fail +# because Rails doesn't have write access. +# +# As an example: +# * https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27581 +# * https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/3267 +# +# # This file needs to be loaded BEFORE any initializers that attempt to # prepend modules that require access to secrets (e.g. EE's 0_as_concern.rb). # diff --git a/config/initializers/seed_fu.rb b/config/initializers/seed_fu.rb new file mode 100644 index 00000000000..2e48e41a311 --- /dev/null +++ b/config/initializers/seed_fu.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true +if Gitlab.ee? + SeedFu.fixture_paths += %W[ee/db/fixtures ee/db/fixtures/#{Rails.env}] +end diff --git a/doc/development/architecture.md b/doc/development/architecture.md index 88c16a8db22..1e59b59b312 100644 --- a/doc/development/architecture.md +++ b/doc/development/architecture.md @@ -322,7 +322,7 @@ graph TB | Jaeger: GitLab instance | View traces generated by the GitLab instance | [❌](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/4104) | [❌](https://gitlab.com/charts/gitlab/issues/1320) | [❌](https://gitlab.com/charts/gitlab/issues/1320) | [❌](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/4104) | CE & EE | | Sentry: deployed apps | Error tracking for deployed apps | [⤓](https://docs.gitlab.com/ee/user/project/operations/error_tracking.html) | [⤓](https://docs.gitlab.com/ee/user/project/operations/error_tracking.html) | [⤓](https://docs.gitlab.com/ee/user/project/operations/error_tracking.html) | [⤓](https://docs.gitlab.com/ee/user/project/operations/error_tracking.html) | CE & EE | | Jaeger: deployed apps | Distributed tracing for deployed apps | [⤓](https://docs.gitlab.com/ee/user/project/operations/tracing.html) | [⤓](https://docs.gitlab.com/ee/user/project/operations/tracing.html) | [⤓](https://docs.gitlab.com/ee/user/project/operations/tracing.html) | [⤓](https://docs.gitlab.com/ee/user/project/operations/tracing.html) | EE Only | -| Kubernetes cluster apps | Deploy [Helm](https://docs.helm.sh/), [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/), [Cert-Manager](https://docs.cert-manager.io/en/latest/), [Prometheus](https://prometheus.io/docs/introduction/overview/), a [Runner](https://docs.gitlab.com/runner/), [JupyterHub](http://jupyter.org/), [Knative](https://cloud.google.com/knative) to a cluster | [⤓](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | [⤓](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | [⤓](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | [⤓](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | CE & EE | +| Kubernetes cluster apps | Deploy [Helm](https://docs.helm.sh/), [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/), [Cert-Manager](https://docs.cert-manager.io/en/latest/), [Prometheus](https://prometheus.io/docs/introduction/overview/), a [Runner](https://docs.gitlab.com/runner/), [JupyterHub](http://jupyter.org/), [Knative](https://cloud.google.com/knative) to a cluster | [✅](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | [✅](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | [✅](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | [✅](https://docs.gitlab.com/ee/user/project/clusters/#installing-applications) | CE & EE | A typical install of GitLab will be on GNU/Linux. It uses Nginx or Apache as a web front end to proxypass the Unicorn web server. By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported. The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and precompiled assets. GitLab serves web pages and a [GitLab API](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/api) using the Unicorn web server. It uses Sidekiq as a job queue which, in turn, uses redis as a non-persistent database backend for job information, meta data, and incoming jobs. diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 5f6123b5f9b..8e06aa5d173 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -43,9 +43,9 @@ new Vue({ Read more about [Vue Apollo][vue-apollo] in the [Vue Apollo documentation][vue-apollo-docs]. -### Local state with `apollo-link-state` +### Local state with Apollo -It is possible to use our Apollo setup with [apollo-link-state][apollo-link-state] by passing +It is possible to manage an application state with Apollo by passing in a resolvers object when creating the default client. The default state can be set by writing to the cache after setting up the default client. @@ -76,6 +76,8 @@ const apolloProvider = new VueApollo({ }); ``` +Read more about local state management with Apollo in the [Vue Apollo documentation](https://vue-apollo.netlify.com/guide/local-state.html#local-state). + ### Testing With [Vue test utils][vue-test-utils] it is easy to quickly test components that @@ -92,6 +94,8 @@ it('tests apollo component', () => { }); ``` +Another possible way is testing queries with mocked GraphQL schema. Read more about this way in [Vue Apollo testing documentation](https://vue-apollo.netlify.com/guide/testing.html#tests-with-mocked-graqhql-schema) + ## Usage outside of Vue It is also possible to use GraphQL outside of Vue by directly importing diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md index f58a8dcbcdc..9bd99e80357 100644 --- a/doc/development/testing_guide/frontend_testing.md +++ b/doc/development/testing_guide/frontend_testing.md @@ -187,6 +187,7 @@ export default function doSomething() { visitUrl('/foo/bar'); } ``` + ```js // my_module_spec.js import doSomething from '~/my_module'; @@ -213,7 +214,187 @@ Further documentation on the babel rewire pluign API can be found on #### Waiting in tests -If you cannot avoid using [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) in tests, please use the [Jasmine mock clock](https://jasmine.github.io/api/2.9/Clock.html). +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 passed a time larger than zero it will slow down our test suite. +Instead use one of the following approaches. + +##### Promises and Ajax calls + +Register handler functions to wait for the `Promise` to be resolved. + +```javascript +const askTheServer = () => { + return axios + .get('/endpoint') + .then(response => { + // do something + }) + .catch(error => { + // do something else + }); +}; +``` + +**in Jest:** + +```javascript +it('waits for an Ajax call', () => { + return askTheServer().then(() => { + expect(something).toBe('done'); + }); +}); +``` + +**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—you can flush all pending `Promise`s: + +**in Jest:** + +```javascript +it('waits for an Ajax call', () => { + synchronousFunction(); + jest.runAllTicks(); + + expect(something).toBe('done'); +}); +``` + +**in Karma:** + +You are out of luck. The following only works sometimes and may lead to flaky failures: + +```javascript +it('waits for an Ajax call', done => { + synchronousFunction(); + + // create a new Promise and hope that it resolves after the rest + Promise.resolve() + .then(() => { + expect(something).toBe('done'); + }) + .then(done) + .catch(done.fail); +}); +``` + +##### Vue rendering + +To wait until a Vue component is re-rendered, use either of the equivalent +[`Vue.nextTick()`](https://vuejs.org/v2/api/#Vue-nextTick) or `vm.$nextTick()`. + +**in Jest:** + +```javascript +it('renders something', () => { + wrapper.setProps({ value: 'new value' }); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.text()).toBe('new value'); + }); +}); +``` + +**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); +}); +``` + +##### `setTimeout()` / `setInterval()` in application + +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-ce/blob/a2128edfee799e49a8732bfa235e2c5e14949c68/jest.config.js#L47) +(see also [Jest Timer Mocks](https://jestjs.io/docs/en/timer-mocks)). In Karma you can use the +[Jasmine mock clock](https://jasmine.github.io/api/2.9/Clock.html). + +```javascript +const doSomethingLater = () => { + setTimeout(() => { + // do something + }, 4000); +}; +``` + +**in Jest:** + +```javascript +it('does something', () => { + doSomethingLater(); + jest.runAllTimers(); + + expect(something).toBe('done'); +}); +``` + +**in Karma:** + +```javascript +it('does something', () => { + jasmine.clock().install(); + + doSomethingLater(); + jasmine.clock().tick(4000); + + expect(something).toBe('done'); + jasmine.clock().uninstall(); +}); +``` + +##### Events + +If the application triggers an event that you need to wait for in your test, register an event handler which contains +the assertions: + +```javascript +it('waits for an event', done => { + eventHub.$once('someEvent', eventHandler); + + someFunction(); + + function eventHandler() { + expect(something).toBe('done'); + done(); + } +}); +``` + +In Jest you can also use a `Promise` for this: + +```javascript +it('waits for an event', () => { + const eventTriggered = new Promise(resolve => eventHub.$once('someEvent', resolve)); + + someFunction(); + + return eventTriggered.then(() => { + expect(something).toBe('done'); + }); +}); +``` #### Migrating flaky Karma tests to Jest diff --git a/doc/integration/salesforce.md b/doc/integration/salesforce.md index 18d42486fd6..8a99641a256 100644 --- a/doc/integration/salesforce.md +++ b/doc/integration/salesforce.md @@ -1,15 +1,15 @@ # SalesForce OmniAuth Provider -You can integrate your GitLab instance with [SalesForce](https://www.salesforce.com/) to enable users to login to your GitLab instance with their SalesForce account. +You can integrate your GitLab instance with [SalesForce](https://www.salesforce.com/) to enable users to login to your GitLab instance with their SalesForce account. ## Create SalesForce Application To enable SalesForce OmniAuth provider, you must use SalesForce's credentials for your GitLab instance. -To get the credentials (a pair of Client ID and Client Secret), you must register an application on UltraAuth. +To get the credentials (a pair of Client ID and Client Secret), you must register an application on SalesForces. 1. Sign in to [SalesForce](https://www.salesforce.com/). -1. Navigate to **Platform Tools/Apps** and click on **New Connected App**. +1. Navigate to **Platform Tools/Apps/App Manager** and click on **New Connected App**. 1. Fill in the application details into the following fields: - **Connected App Name** and **API Name**: Set to any value but consider something like `<Organization>'s GitLab`, `<Your Name>'s GitLab`, or something else that is descriptive. @@ -64,7 +64,7 @@ To get the credentials (a pair of Client ID and Client Secret), you must registe } ``` 1. Change `SALESFORCE_CLIENT_ID` to the Consumer Key from the SalesForce connected application page. -1. Change `SALESFORCE_CLIENT_SECRET` to the Client Secret from the SalesForce connected application page. +1. Change `SALESFORCE_CLIENT_SECRET` to the Consumer Secret from the SalesForce connected application page. ![SalesForce App Secret Details](img/salesforce_app_secret_details.png) 1. Save the configuration file. diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 834a1e2423a..42fc4efa4ce 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -98,8 +98,7 @@ the group. NOTE: **Note:** Only available on GitLab.com. -If you have a Group with a [paid plan](https://about.gitlab.com/pricing/#gitlab-com) on GitLab.com, -then you can purchase additional CI minutes so your pipelines will not be blocked after you have +You can purchase additional CI minutes so your pipelines will not be blocked after you have used all your CI minutes from your main quota. In order to purchase additional minutes, you should follow these steps: diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md index 8e1603f9ec9..10eb3a4f3b7 100644 --- a/doc/user/project/integrations/webhooks.md +++ b/doc/user/project/integrations/webhooks.md @@ -321,8 +321,14 @@ X-Gitlab-Event: Issue Hook "group_id": 41 }], "changes": { - "updated_by_id": [null, 1], - "updated_at": ["2017-09-15 16:50:55 UTC", "2017-09-15 16:52:00 UTC"], + "updated_by_id": { + "previous": null, + "current": 1 + }, + "updated_at": { + "previous": "2017-09-15 16:50:55 UTC", + "current": "2017-09-15 16:52:00 UTC" + }, "labels": { "previous": [{ "id": 206, @@ -851,8 +857,14 @@ X-Gitlab-Event: Merge Request Hook "group_id": 41 }], "changes": { - "updated_by_id": [null, 1], - "updated_at": ["2017-09-15 16:50:55 UTC", "2017-09-15 16:52:00 UTC"], + "updated_by_id": { + "previous": null, + "current": 1 + }, + "updated_at": { + "previous": "2017-09-15 16:50:55 UTC", + "current":"2017-09-15 16:52:00 UTC" + }, "labels": { "previous": [{ "id": 206, diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md index 6c3fa5eb463..d36312c9b8d 100644 --- a/doc/user/project/new_ci_build_permissions_model.md +++ b/doc/user/project/new_ci_build_permissions_model.md @@ -44,14 +44,14 @@ It is important to note that we have a few types of users: - **Administrators**: CI jobs created by Administrators will not have access to all GitLab projects, but only to projects and container images of projects - that the administrator is a member of.That means that if a project is either + that the administrator is a member of. That means that if a project is either public or internal users have access anyway, but if a project is private, the Administrator will have to be a member of it in order to have access to it via another project's job. - **External users**: CI jobs created by [external users](../permissions.md#external-users-permissions) will have access only to projects to which user has at least reporter access. This - rules out accessing all internal projects by default, + rules out accessing all internal projects by default. This allows us to make the CI and permission system more trustworthy. Let's consider the following scenario: diff --git a/package.json b/package.json index eb557101662..f19baac0229 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,17 @@ { "private": true, "scripts": { + "check-dependencies": "yarn check --integrity", "clean": "rm -rf public/assets tmp/cache/*-loader", "dev-server": "NODE_OPTIONS=\"--max-old-space-size=3584\" nodemon -w 'config/webpack.config.js' --exec 'webpack-dev-server --config config/webpack.config.js'", "eslint": "eslint --max-warnings 0 --report-unused-disable-directives --ext .js,.vue .", "eslint-fix": "eslint --max-warnings 0 --report-unused-disable-directives --ext .js,.vue --fix .", "eslint-report": "eslint --max-warnings 0 --ext .js,.vue --format html --output-file ./eslint-report.html --no-inline-config .", + "prejest": "yarn check-dependencies", + "jest": "jest", "jest-debug": "node --inspect-brk node_modules/.bin/jest --runInBand", "jsdoc": "jsdoc -c config/jsdocs.config.js", + "prekarma": "yarn check-dependencies", "karma": "BABEL_ENV=${BABEL_ENV:=karma} karma start --single-run true config/karma.config.js", "karma-coverage": "BABEL_ENV=coverage karma start --single-run true config/karma.config.js", "karma-start": "BABEL_ENV=karma karma start config/karma.config.js", diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 9fabf83e2ce..c395e5f6011 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -113,8 +113,8 @@ module QA has_css?(element_selector_css(name), wait: wait, text: text) end - def has_no_element?(name, wait: Capybara.default_max_wait_time) - has_no_css?(element_selector_css(name), wait: wait) + def has_no_element?(name, text: nil, wait: Capybara.default_max_wait_time) + has_no_css?(element_selector_css(name), wait: wait, text: text) end def has_text?(text) @@ -129,8 +129,8 @@ module QA has_no_css?('.fa-spinner', wait: Capybara.default_max_wait_time) end - def within_element(name) - page.within(element_selector_css(name)) do + def within_element(name, text: nil) + page.within(element_selector_css(name), text: text) do yield end end diff --git a/qa/qa/page/project/branches/show.rb b/qa/qa/page/project/branches/show.rb index 922a6ddb086..762eacdab15 100644 --- a/qa/qa/page/project/branches/show.rb +++ b/qa/qa/page/project/branches/show.rb @@ -7,6 +7,7 @@ module QA class Show < Page::Base view 'app/views/projects/branches/_branch.html.haml' do element :remove_btn + element :branch_name end view 'app/views/projects/branches/_panel.html.haml' do element :all_branches @@ -27,11 +28,9 @@ module QA finished_loading? end - def has_branch_title?(branch_title) + def has_no_branch?(branch_name) within_element(:all_branches) do - within(".item-title") do - has_text?(branch_title) - end + has_no_element?(:branch_name, text: branch_name, wait: Support::Waiter::DEFAULT_MAX_WAIT_TIME) end end @@ -48,15 +47,6 @@ module QA click_element(:delete_merged_branches) end end - - def wait_for_texts_not_to_be_visible(texts) - text_not_visible = wait do - texts.all? do |text| - has_no_text?(text) - end - end - raise "Expected text(s) #{texts} not to be visible" unless text_not_visible - end end end end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb index c2c2b6da90a..cf6c24fa873 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb @@ -73,10 +73,9 @@ module QA Page::Project::Branches::Show.perform do |branches_view| branches_view.delete_branch(third_branch) + expect(branches_view).to have_no_branch(third_branch) end - expect(page).not_to have_content(third_branch) - Page::Project::Branches::Show.perform(&:delete_merged_branches) expect(page).to have_content( @@ -85,8 +84,7 @@ module QA page.refresh Page::Project::Branches::Show.perform do |branches_view| - branches_view.wait_for_texts_not_to_be_visible([commit_message_of_second_branch]) - expect(branches_view).not_to have_branch_title(second_branch) + expect(branches_view).to have_no_branch(second_branch) end end end diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb index 69b6332ecce..ff505fdbddd 100644 --- a/qa/qa/support/page/logging.rb +++ b/qa/qa/support/page/logging.rb @@ -76,23 +76,18 @@ module QA super end - def has_element?(name, text: nil, wait: Capybara.default_max_wait_time) + def has_element?(name, **kwargs) found = super - msg = ["has_element? :#{name}"] - msg << %Q(with text "#{text}") if text - msg << "(wait: #{wait})" - msg << "returned: #{found}" - - log(msg.compact.join(' ')) + log_has_element_or_not('has_element?', name, found, **kwargs) found end - def has_no_element?(name, wait: Capybara.default_max_wait_time) + def has_no_element?(name, **kwargs) found = super - log("has_no_element? :#{name} returned #{found}") + log_has_element_or_not('has_no_element?', name, found, **kwargs) found end @@ -149,6 +144,15 @@ module QA def log(msg) QA::Runtime::Logger.debug(msg) end + + def log_has_element_or_not(method, name, found, **kwargs) + msg = ["#{method} :#{name}"] + msg << %Q(with text "#{kwargs[:text]}") if kwargs[:text] + msg << "(wait: #{kwargs[:wait] || Capybara.default_max_wait_time})" + msg << "returned: #{found}" + + log(msg.compact.join(' ')) + end end end end diff --git a/qa/qa/support/waiter.rb b/qa/qa/support/waiter.rb index 21a399b4a5f..fdcf2d7e157 100644 --- a/qa/qa/support/waiter.rb +++ b/qa/qa/support/waiter.rb @@ -3,9 +3,11 @@ module QA module Support module Waiter + DEFAULT_MAX_WAIT_TIME = 60 + module_function - def wait(max: 60, interval: 0.1) + def wait(max: DEFAULT_MAX_WAIT_TIME, interval: 0.1) QA::Runtime::Logger.debug("with wait: max #{max}; interval #{interval}") start = Time.now diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb index 707a7ff6d98..99e96b81a51 100644 --- a/qa/spec/page/logging_spec.rb +++ b/qa/spec/page/logging_spec.rb @@ -93,7 +93,14 @@ describe QA::Support::Page::Logging do allow(page).to receive(:has_no_css?).and_return(true) expect { subject.has_no_element?(:element) } - .to output(/has_no_element\? :element returned true/).to_stdout_from_any_process + .to output(/has_no_element\? :element \(wait: 2\) returned: true/).to_stdout_from_any_process + end + + it 'logs has_no_element? with text' do + allow(page).to receive(:has_no_css?).and_return(true) + + expect { subject.has_no_element?(:element, text: "more text") } + .to output(/has_no_element\? :element with text \"more text\" \(wait: 2\) returned: true/).to_stdout_from_any_process end it 'logs has_text?' do diff --git a/spec/javascripts/fixtures/abuse_reports.rb b/spec/javascripts/fixtures/abuse_reports.rb index 54b6419bcdb..e0aaecf626a 100644 --- a/spec/javascripts/fixtures/abuse_reports.rb +++ b/spec/javascripts/fixtures/abuse_reports.rb @@ -18,10 +18,9 @@ describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :controll sign_in(admin) end - it 'abuse_reports/abuse_reports_list.html' do |example| + it 'abuse_reports/abuse_reports_list.html' do get :index expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/admin_users.rb b/spec/javascripts/fixtures/admin_users.rb index 76dbdf603da..22a5de66577 100644 --- a/spec/javascripts/fixtures/admin_users.rb +++ b/spec/javascripts/fixtures/admin_users.rb @@ -17,13 +17,12 @@ describe Admin::UsersController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('admin/users') end - it 'admin/users/new_with_internal_user_regex.html' do |example| + it 'admin/users/new_with_internal_user_regex.html' do stub_application_setting(user_default_external: true) stub_application_setting(user_default_internal_regex: '^(?:(?!\.ext@).)*$\r?') get :new expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/application_settings.rb b/spec/javascripts/fixtures/application_settings.rb index c535e598e12..d4651fa6ece 100644 --- a/spec/javascripts/fixtures/application_settings.rb +++ b/spec/javascripts/fixtures/application_settings.rb @@ -23,12 +23,11 @@ describe Admin::ApplicationSettingsController, '(JavaScript fixtures)', type: :c remove_repository(project) end - it 'application_settings/accounts_and_limit.html' do |example| + it 'application_settings/accounts_and_limit.html' do stub_application_setting(user_default_external: false) get :show expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/autocomplete_sources.rb b/spec/javascripts/fixtures/autocomplete_sources.rb index c117fb7cd24..b20a0159d7d 100644 --- a/spec/javascripts/fixtures/autocomplete_sources.rb +++ b/spec/javascripts/fixtures/autocomplete_sources.rb @@ -18,7 +18,7 @@ describe Projects::AutocompleteSourcesController, '(JavaScript fixtures)', type: sign_in(admin) end - it 'autocomplete_sources/labels.json' do |example| + it 'autocomplete_sources/labels.json' do issue.labels << create(:label, project: project, title: 'bug') issue.labels << create(:label, project: project, title: 'critical') @@ -35,6 +35,5 @@ describe Projects::AutocompleteSourcesController, '(JavaScript fixtures)', type: } expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/balsamiq.rb b/spec/javascripts/fixtures/balsamiq.rb deleted file mode 100644 index 234e246119a..00000000000 --- a/spec/javascripts/fixtures/balsamiq.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -describe 'Balsamiq file', '(JavaScript fixtures)', type: :controller do - include JavaScriptFixturesHelpers - - let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, :repository, namespace: namespace, path: 'balsamiq-project') } - - before(:all) do - clean_frontend_fixtures('blob/balsamiq/') - end - - it 'blob/balsamiq/test.bmpr' do |example| - blob = project.repository.blob_at('b89b56d79', 'files/images/balsamiq.bmpr') - - store_frontend_fixture(blob.data.force_encoding('utf-8'), example.description) - end -end diff --git a/spec/javascripts/fixtures/blob.rb b/spec/javascripts/fixtures/blob.rb index db7749bc000..07670552cd5 100644 --- a/spec/javascripts/fixtures/blob.rb +++ b/spec/javascripts/fixtures/blob.rb @@ -22,7 +22,7 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'blob/show.html' do |example| + it 'blob/show.html' do get(:show, params: { namespace_id: project.namespace, project_id: project, @@ -30,6 +30,5 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do }) expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb index c4390e89578..5835721d3d5 100644 --- a/spec/javascripts/fixtures/boards.rb +++ b/spec/javascripts/fixtures/boards.rb @@ -17,13 +17,12 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller sign_in(admin) end - it 'boards/show.html' do |example| + it 'boards/show.html' do get(:index, params: { namespace_id: project.namespace, project_id: project }) expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb index 5d2d6c7ec0e..204aa9b7c7a 100644 --- a/spec/javascripts/fixtures/branches.rb +++ b/spec/javascripts/fixtures/branches.rb @@ -21,13 +21,12 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'branches/new_branch.html' do |example| + it 'branches/new_branch.html' do get :new, params: { namespace_id: project.namespace.to_param, project_id: project } expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/clusters.rb b/spec/javascripts/fixtures/clusters.rb index 8ebd8a41366..1076404e0e3 100644 --- a/spec/javascripts/fixtures/clusters.rb +++ b/spec/javascripts/fixtures/clusters.rb @@ -22,7 +22,7 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'clusters/show_cluster.html' do |example| + it 'clusters/show_cluster.html' do get :show, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -30,6 +30,5 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle } expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/commit.rb b/spec/javascripts/fixtures/commit.rb index ab10f559e4b..ff9a4bc1adc 100644 --- a/spec/javascripts/fixtures/commit.rb +++ b/spec/javascripts/fixtures/commit.rb @@ -19,7 +19,7 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller allow(SecureRandom).to receive(:hex).and_return('securerandomhex:thereisnospoon') end - it 'commit/show.html' do |example| + it 'commit/show.html' do params = { namespace_id: project.namespace, project_id: project, @@ -29,6 +29,5 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller get :show, params: params expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/deploy_keys.rb b/spec/javascripts/fixtures/deploy_keys.rb index a333d9c0150..38eab853da2 100644 --- a/spec/javascripts/fixtures/deploy_keys.rb +++ b/spec/javascripts/fixtures/deploy_keys.rb @@ -24,7 +24,7 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control render_views - it 'deploy_keys/keys.json' do |example| + it 'deploy_keys/keys.json' do create(:rsa_deploy_key_2048, public: true) project_key = create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCdMHEHyhRjbhEZVddFn6lTWdgEy5Q6Bz4nwGB76xWZI5YT/1WJOMEW+sL5zYd31kk7sd3FJ5L9ft8zWMWrr/iWXQikC2cqZK24H1xy+ZUmrRuJD4qGAaIVoyyzBL+avL+lF8J5lg6YSw8gwJY/lX64/vnJHUlWw2n5BF8IFOWhiw== dummy@gitlab.com') internal_key = create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNd/UJWhPrpb+b/G5oL109y57yKuCxE+WUGJGYaj7WQKsYRJmLYh1mgjrl+KVyfsWpq4ylOxIfFSnN9xBBFN8mlb0Fma5DC7YsSsibJr3MZ19ZNBprwNcdogET7aW9I0In7Wu5f2KqI6e5W/spJHCy4JVxzVMUvk6Myab0LnJ2iQ== dummy@gitlab.com') @@ -39,6 +39,5 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control }, format: :json expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/groups.rb b/spec/javascripts/fixtures/groups.rb index 16e31028b05..4d0afc3ce1a 100644 --- a/spec/javascripts/fixtures/groups.rb +++ b/spec/javascripts/fixtures/groups.rb @@ -18,20 +18,18 @@ describe 'Groups (JavaScript fixtures)', type: :controller do end describe GroupsController, '(JavaScript fixtures)', type: :controller do - it 'groups/edit.html' do |example| + it 'groups/edit.html' do get :edit, params: { id: group } expect(response).to be_success - store_frontend_fixture(response, example.description) end end describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do - it 'groups/ci_cd_settings.html' do |example| + it 'groups/ci_cd_settings.html' do get :show, params: { group_id: group } expect(response).to be_success - store_frontend_fixture(response, example.description) end end end diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb index 0f3f9a10f94..d8d77f767de 100644 --- a/spec/javascripts/fixtures/issues.rb +++ b/spec/javascripts/fixtures/issues.rb @@ -21,26 +21,26 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller remove_repository(project) end - it 'issues/open-issue.html' do |example| - render_issue(example.description, create(:issue, project: project)) + it 'issues/open-issue.html' do + render_issue(create(:issue, project: project)) end - it 'issues/closed-issue.html' do |example| - render_issue(example.description, create(:closed_issue, project: project)) + it 'issues/closed-issue.html' do + render_issue(create(:closed_issue, project: project)) end - it 'issues/issue-with-task-list.html' do |example| + it 'issues/issue-with-task-list.html' do issue = create(:issue, project: project, description: '- [ ] Task List Item') - render_issue(example.description, issue) + render_issue(issue) end - it 'issues/issue_with_comment.html' do |example| + it 'issues/issue_with_comment.html' do issue = create(:issue, project: project) create(:note, project: project, noteable: issue, note: '- [ ] Task List Item').save - render_issue(example.description, issue) + render_issue(issue) end - it 'issues/issue_list.html' do |example| + it 'issues/issue_list.html' do create(:issue, project: project) get :index, params: { @@ -49,12 +49,11 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller } expect(response).to be_success - store_frontend_fixture(response, example.description) end private - def render_issue(fixture_file_name, issue) + def render_issue(issue) get :show, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -62,7 +61,6 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller } expect(response).to be_success - store_frontend_fixture(response, fixture_file_name) end end @@ -89,7 +87,7 @@ describe API::Issues, '(JavaScript fixtures)', type: :request do end end - it 'issues/related_merge_requests.json' do |example| + it 'issues/related_merge_requests.json' do user = create(:user) project = create(:project, :public, creator_id: user.id, namespace: user.namespace) issue_title = 'foo' @@ -120,6 +118,5 @@ describe API::Issues, '(JavaScript fixtures)', type: :request do get_related_merge_requests(project.id, issue.iid, user) expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb index 941235190b5..46ccd6f8c8a 100644 --- a/spec/javascripts/fixtures/jobs.rb +++ b/spec/javascripts/fixtures/jobs.rb @@ -32,7 +32,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'builds/build-with-artifacts.html' do |example| + it 'builds/build-with-artifacts.html' do get :show, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -40,10 +40,9 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do } expect(response).to be_success - store_frontend_fixture(response, example.description) end - it 'jobs/delayed.json' do |example| + it 'jobs/delayed.json' do get :show, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -51,6 +50,5 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do }, format: :json expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/labels.rb b/spec/javascripts/fixtures/labels.rb index 9420194e675..4d1b7317274 100644 --- a/spec/javascripts/fixtures/labels.rb +++ b/spec/javascripts/fixtures/labels.rb @@ -30,13 +30,12 @@ describe 'Labels (JavaScript fixtures)' do sign_in(admin) end - it 'labels/group_labels.json' do |example| + it 'labels/group_labels.json' do get :index, params: { group_id: group }, format: 'json' expect(response).to be_success - store_frontend_fixture(response, example.description) end end @@ -47,14 +46,13 @@ describe 'Labels (JavaScript fixtures)' do sign_in(admin) end - it 'labels/project_labels.json' do |example| + it 'labels/project_labels.json' do get :index, params: { namespace_id: group, project_id: project }, format: 'json' expect(response).to be_success - store_frontend_fixture(response, example.description) end end end diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 7df1e5cb512..05860be2291 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -42,52 +42,52 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont remove_repository(project) end - it 'merge_requests/merge_request_of_current_user.html' do |example| + it 'merge_requests/merge_request_of_current_user.html' do merge_request.update(author: admin) - render_merge_request(example.description, merge_request) + render_merge_request(merge_request) end - it 'merge_requests/merge_request_with_task_list.html' do |example| + it 'merge_requests/merge_request_with_task_list.html' do create(:ci_build, :pending, pipeline: pipeline) - render_merge_request(example.description, merge_request) + render_merge_request(merge_request) end - it 'merge_requests/merged_merge_request.html' do |example| + it 'merge_requests/merged_merge_request.html' do expect_next_instance_of(MergeRequest) do |merge_request| allow(merge_request).to receive(:source_branch_exists?).and_return(true) allow(merge_request).to receive(:can_remove_source_branch?).and_return(true) end - render_merge_request(example.description, merged_merge_request) + render_merge_request(merged_merge_request) end - it 'merge_requests/diff_comment.html' do |example| + it 'merge_requests/diff_comment.html' do create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) create(:note_on_merge_request, author: admin, project: project, noteable: merge_request) - render_merge_request(example.description, merge_request) + render_merge_request(merge_request) end - it 'merge_requests/merge_request_with_comment.html' do |example| + it 'merge_requests/merge_request_with_comment.html' do create(:note_on_merge_request, author: admin, project: project, noteable: merge_request, note: '- [ ] Task List Item') - render_merge_request(example.description, merge_request) + render_merge_request(merge_request) end - it 'merge_requests/discussions.json' do |example| + it 'merge_requests/discussions.json' do create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) - render_discussions_json(merge_request, example.description) + render_discussions_json(merge_request) end - it 'merge_requests/diff_discussion.json' do |example| + it 'merge_requests/diff_discussion.json' do create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) - render_discussions_json(merge_request, example.description) + render_discussions_json(merge_request) end - it 'merge_requests/resolved_diff_discussion.json' do |example| + it 'merge_requests/resolved_diff_discussion.json' do note = create(:discussion_note_on_merge_request, :resolved, project: project, author: admin, position: position, noteable: merge_request) create(:system_note, project: project, author: admin, noteable: merge_request, discussion_id: note.discussion.id) - render_discussions_json(merge_request, example.description) + render_discussions_json(merge_request) end context 'with image diff' do @@ -106,25 +106,23 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont ) end - it 'merge_requests/image_diff_discussion.json' do |example| + it 'merge_requests/image_diff_discussion.json' do create(:diff_note_on_merge_request, project: project, noteable: merge_request2, position: image_position) - render_discussions_json(merge_request2, example.description) + render_discussions_json(merge_request2) end end private - def render_discussions_json(merge_request, fixture_file_name) + def render_discussions_json(merge_request) get :discussions, params: { namespace_id: project.namespace.to_param, project_id: project, id: merge_request.to_param }, format: :json - - store_frontend_fixture(response, fixture_file_name) end - def render_merge_request(fixture_file_name, merge_request) + def render_merge_request(merge_request) get :show, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -132,6 +130,5 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont }, format: :html expect(response).to be_success - store_frontend_fixture(response, fixture_file_name) end end diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb index 57462e74bb2..03b9b713fd8 100644 --- a/spec/javascripts/fixtures/merge_requests_diffs.rb +++ b/spec/javascripts/fixtures/merge_requests_diffs.rb @@ -34,29 +34,29 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type remove_repository(project) end - it 'merge_request_diffs/with_commit.json' do |example| + it 'merge_request_diffs/with_commit.json' do # Create a user that matches the selected commit author # This is so that the "author" information will be populated create(:user, email: selected_commit.author_email, name: selected_commit.author_name) - render_merge_request(example.description, merge_request, commit_id: selected_commit.sha) + render_merge_request(merge_request, commit_id: selected_commit.sha) end - it 'merge_request_diffs/inline_changes_tab_with_comments.json' do |example| + it 'merge_request_diffs/inline_changes_tab_with_comments.json' do create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) create(:note_on_merge_request, author: admin, project: project, noteable: merge_request) - render_merge_request(example.description, merge_request) + render_merge_request(merge_request) end - it 'merge_request_diffs/parallel_changes_tab_with_comments.json' do |example| + it 'merge_request_diffs/parallel_changes_tab_with_comments.json' do create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) create(:note_on_merge_request, author: admin, project: project, noteable: merge_request) - render_merge_request(example.description, merge_request, view: 'parallel') + render_merge_request(merge_request, view: 'parallel') end private - def render_merge_request(fixture_file_name, merge_request, view: 'inline', **extra_params) + def render_merge_request(merge_request, view: 'inline', **extra_params) get :show, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -66,6 +66,5 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type }, format: :json expect(response).to be_success - store_frontend_fixture(response, fixture_file_name) end end diff --git a/spec/javascripts/fixtures/pdf.rb b/spec/javascripts/fixtures/pdf.rb deleted file mode 100644 index ef9976b9fd3..00000000000 --- a/spec/javascripts/fixtures/pdf.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -describe 'PDF file', '(JavaScript fixtures)', type: :controller do - include JavaScriptFixturesHelpers - - let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, :repository, namespace: namespace, path: 'pdf-project') } - - before(:all) do - clean_frontend_fixtures('blob/pdf/') - end - - it 'blob/pdf/test.pdf' do |example| - blob = project.repository.blob_at('e774ebd33', 'files/pdf/test.pdf') - - store_frontend_fixture(blob.data.force_encoding("utf-8"), example.description) - end -end diff --git a/spec/javascripts/fixtures/pipeline_schedules.rb b/spec/javascripts/fixtures/pipeline_schedules.rb index e5176a58273..aecd56e6198 100644 --- a/spec/javascripts/fixtures/pipeline_schedules.rb +++ b/spec/javascripts/fixtures/pipeline_schedules.rb @@ -21,7 +21,7 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : sign_in(admin) end - it 'pipeline_schedules/edit.html' do |example| + it 'pipeline_schedules/edit.html' do get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -29,10 +29,9 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : } expect(response).to be_success - store_frontend_fixture(response, example.description) end - it 'pipeline_schedules/edit_with_variables.html' do |example| + it 'pipeline_schedules/edit_with_variables.html' do get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -40,6 +39,5 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : } expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/pipelines.rb b/spec/javascripts/fixtures/pipelines.rb index 42b552e81c0..de6fcfe10f4 100644 --- a/spec/javascripts/fixtures/pipelines.rb +++ b/spec/javascripts/fixtures/pipelines.rb @@ -23,13 +23,12 @@ describe Projects::PipelinesController, '(JavaScript fixtures)', type: :controll sign_in(admin) end - it 'pipelines/pipelines.json' do |example| + it 'pipelines/pipelines.json' do get :index, params: { namespace_id: namespace, project_id: project }, format: :json expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index 446da83a7f9..94c59207898 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -28,49 +28,45 @@ describe 'Projects (JavaScript fixtures)', type: :controller do end describe ProjectsController, '(JavaScript fixtures)', type: :controller do - it 'projects/dashboard.html' do |example| + it 'projects/dashboard.html' do get :show, params: { namespace_id: project.namespace.to_param, id: project } expect(response).to be_success - store_frontend_fixture(response, example.description) end - it 'projects/overview.html' do |example| + it 'projects/overview.html' do get :show, params: { namespace_id: project_with_repo.namespace.to_param, id: project_with_repo } expect(response).to be_success - store_frontend_fixture(response, example.description) end - it 'projects/edit.html' do |example| + it 'projects/edit.html' do get :edit, params: { namespace_id: project.namespace.to_param, id: project } expect(response).to be_success - store_frontend_fixture(response, example.description) end end describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do - it 'projects/ci_cd_settings.html' do |example| + it 'projects/ci_cd_settings.html' do get :show, params: { namespace_id: project.namespace.to_param, project_id: project } expect(response).to be_success - store_frontend_fixture(response, example.description) end - it 'projects/ci_cd_settings_with_variables.html' do |example| + it 'projects/ci_cd_settings_with_variables.html' do create(:ci_variable, project: project_variable_populated) create(:ci_variable, project: project_variable_populated) @@ -80,7 +76,6 @@ describe 'Projects (JavaScript fixtures)', type: :controller do } expect(response).to be_success - store_frontend_fixture(response, example.description) end end end diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb index 29dc95305b7..f3171fdd97b 100644 --- a/spec/javascripts/fixtures/prometheus_service.rb +++ b/spec/javascripts/fixtures/prometheus_service.rb @@ -22,7 +22,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'services/prometheus/prometheus_service.html' do |example| + it 'services/prometheus/prometheus_service.html' do get :edit, params: { namespace_id: namespace, project_id: project, @@ -30,6 +30,5 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle } expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/raw.rb b/spec/javascripts/fixtures/raw.rb index 82770beb39b..801c80a0112 100644 --- a/spec/javascripts/fixtures/raw.rb +++ b/spec/javascripts/fixtures/raw.rb @@ -1,34 +1,39 @@ require 'spec_helper' -describe 'Raw files', '(JavaScript fixtures)', type: :controller do +describe 'Raw files', '(JavaScript fixtures)' do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:project) { create(:project, :repository, namespace: namespace, path: 'raw-project') } + let(:response) { @blob.data.force_encoding('UTF-8') } before(:all) do + clean_frontend_fixtures('blob/balsamiq/') clean_frontend_fixtures('blob/notebook/') + clean_frontend_fixtures('blob/pdf/') end after do remove_repository(project) end - it 'blob/notebook/basic.json' do |example| - blob = project.repository.blob_at('6d85bb69', 'files/ipython/basic.ipynb') - - store_frontend_fixture(blob.data, example.description) + it 'blob/balsamiq/test.bmpr' do + @blob = project.repository.blob_at('b89b56d79', 'files/images/balsamiq.bmpr') end - it 'blob/notebook/worksheets.json' do |example| - blob = project.repository.blob_at('6d85bb69', 'files/ipython/worksheets.ipynb') + it 'blob/notebook/basic.json' do + @blob = project.repository.blob_at('6d85bb69', 'files/ipython/basic.ipynb') + end - store_frontend_fixture(blob.data, example.description) + it 'blob/notebook/worksheets.json' do + @blob = project.repository.blob_at('6d85bb69', 'files/ipython/worksheets.ipynb') end - it 'blob/notebook/math.json' do |example| - blob = project.repository.blob_at('93ee732', 'files/ipython/math.ipynb') + it 'blob/notebook/math.json' do + @blob = project.repository.blob_at('93ee732', 'files/ipython/math.ipynb') + end - store_frontend_fixture(blob.data, example.description) + it 'blob/pdf/test.pdf' do + @blob = project.repository.blob_at('e774ebd33', 'files/pdf/test.pdf') end end diff --git a/spec/javascripts/fixtures/search.rb b/spec/javascripts/fixtures/search.rb index 5f5b4d4e60d..22fc546d761 100644 --- a/spec/javascripts/fixtures/search.rb +++ b/spec/javascripts/fixtures/search.rb @@ -9,10 +9,9 @@ describe SearchController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('search/') end - it 'search/show.html' do |example| + it 'search/show.html' do get :show expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/services.rb b/spec/javascripts/fixtures/services.rb index dc7ee484c22..2237702ccca 100644 --- a/spec/javascripts/fixtures/services.rb +++ b/spec/javascripts/fixtures/services.rb @@ -22,7 +22,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'services/edit_service.html' do |example| + it 'services/edit_service.html' do get :edit, params: { namespace_id: namespace, project_id: project, @@ -30,6 +30,5 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle } expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/sessions.rb b/spec/javascripts/fixtures/sessions.rb index 8656dea696a..92b74c01c89 100644 --- a/spec/javascripts/fixtures/sessions.rb +++ b/spec/javascripts/fixtures/sessions.rb @@ -16,11 +16,10 @@ describe 'Sessions (JavaScript fixtures)' do set_devise_mapping(context: @request) end - it 'sessions/new.html' do |example| + it 'sessions/new.html' do get :new expect(response).to be_success - store_frontend_fixture(response, example.description) end end end diff --git a/spec/javascripts/fixtures/snippet.rb b/spec/javascripts/fixtures/snippet.rb index ebc5b793166..ace84b14eb7 100644 --- a/spec/javascripts/fixtures/snippet.rb +++ b/spec/javascripts/fixtures/snippet.rb @@ -23,12 +23,11 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'snippets/show.html' do |example| + it 'snippets/show.html' do create(:discussion_note_on_snippet, noteable: snippet, project: project, author: admin, note: '- [ ] Task List Item') get(:show, params: { id: snippet.to_param }) expect(response).to be_success - store_frontend_fixture(response, example.description) end end diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index 6e37a2e5a4c..d0c8a6eca01 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -26,11 +26,10 @@ describe 'Todos (JavaScript fixtures)' do sign_in(admin) end - it 'todos/todos.html' do |example| + it 'todos/todos.html' do get :index expect(response).to be_success - store_frontend_fixture(response, example.description) end end @@ -41,7 +40,7 @@ describe 'Todos (JavaScript fixtures)' do sign_in(admin) end - it 'todos/todos.json' do |example| + it 'todos/todos.json' do post :create, params: { namespace_id: namespace, project_id: project, @@ -50,7 +49,6 @@ describe 'Todos (JavaScript fixtures)' do }, format: 'json' expect(response).to be_success - store_frontend_fixture(response, example.description) end end end diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb index 15866d65a4f..f52832b6efb 100644 --- a/spec/javascripts/fixtures/u2f.rb +++ b/spec/javascripts/fixtures/u2f.rb @@ -18,13 +18,12 @@ context 'U2F' do set_devise_mapping(context: @request) end - it 'u2f/authenticate.html' do |example| + it 'u2f/authenticate.html' do allow(controller).to receive(:find_user).and_return(user) post :create, params: { user: { login: user.username, password: user.password } } expect(response).to be_success - store_frontend_fixture(response, example.description) end end @@ -36,11 +35,10 @@ context 'U2F' do allow_any_instance_of(Profiles::TwoFactorAuthsController).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares') end - it 'u2f/register.html' do |example| + it 'u2f/register.html' do get :show expect(response).to be_success - store_frontend_fixture(response, example.description) end end end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 4a7eee1fbf3..04ae9390436 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -166,6 +166,13 @@ describe JiraService do ).once end + it 'does not fail if remote_link.all on issue returns nil' do + allow(JIRA::Resource::Remotelink).to receive(:all).and_return(nil) + + expect { @jira_service.close_issue(resource, ExternalIssue.new('JIRA-123', project)) } + .not_to raise_error(NoMethodError) + end + # Check https://developer.atlassian.com/jiradev/jira-platform/guides/other/guide-jira-remote-issue-links/fields-in-remote-issue-links # for more information it 'creates Remote Link reference in JIRA for comment' do diff --git a/spec/services/projects/after_import_service_spec.rb b/spec/services/projects/after_import_service_spec.rb index 95c11f71c5e..51d3fd18881 100644 --- a/spec/services/projects/after_import_service_spec.rb +++ b/spec/services/projects/after_import_service_spec.rb @@ -15,7 +15,7 @@ describe Projects::AfterImportService do describe '#execute' do before do allow(Projects::HousekeepingService) - .to receive(:new).with(project, :gc).and_return(housekeeping_service) + .to receive(:new).with(project).and_return(housekeeping_service) allow(housekeeping_service) .to receive(:execute).and_yield diff --git a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb index d8427d0bf78..80debcd3a7a 100644 --- a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb @@ -33,7 +33,10 @@ describe Projects::LfsPointers::LfsDownloadLinkListService do before do allow(project).to receive(:lfs_enabled?).and_return(true) - allow(Gitlab::HTTP).to receive(:post).and_return(objects_response) + response = instance_double(HTTParty::Response) + allow(response).to receive(:body).and_return(objects_response.to_json) + allow(response).to receive(:success?).and_return(true) + allow(Gitlab::HTTP).to receive(:post).and_return(response) end describe '#execute' do @@ -89,6 +92,21 @@ describe Projects::LfsPointers::LfsDownloadLinkListService do expect { subject.send(:get_download_links, new_oids) }.to raise_error(described_class::DownloadLinksError) end + + shared_examples 'JSON parse errors' do |body| + it 'raises error' do + response = instance_double(HTTParty::Response) + allow(response).to receive(:body).and_return(body) + allow(response).to receive(:success?).and_return(true) + allow(Gitlab::HTTP).to receive(:post).and_return(response) + + expect { subject.send(:get_download_links, new_oids) }.to raise_error(described_class::DownloadLinksError) + end + end + + it_behaves_like 'JSON parse errors', '{' + it_behaves_like 'JSON parse errors', '{}' + it_behaves_like 'JSON parse errors', '{ foo: 123 }' end describe '#parse_response_links' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9266bee34d6..69589c9aa33 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -138,7 +138,7 @@ RSpec.configure do |config| .and_return(false) end - config.before(:example, :quarantine) do + config.around(:example, :quarantine) do # Skip tests in quarantine unless we explicitly focus on them. skip('In quarantine') unless config.inclusion_filter[:quarantine] end diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index f15944652fd..44ed9da25fc 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -197,3 +197,7 @@ module GraphqlHelpers allow(GitlabSchema).to receive(:max_query_depth).with(any_args).and_return nil end end + +# This warms our schema, doing this as part of loading the helpers to avoid +# duplicate loading error when Rails tries autoload the types. +GitlabSchema.graphql_definition diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb index 494398dc4de..cdd7724cc13 100644 --- a/spec/support/helpers/javascript_fixtures_helpers.rb +++ b/spec/support/helpers/javascript_fixtures_helpers.rb @@ -11,6 +11,10 @@ module JavaScriptFixturesHelpers base.around do |example| # pick an arbitrary date from the past, so tests are not time dependent Timecop.freeze(Time.utc(2015, 7, 3, 10)) { example.run } + + raise NoMethodError.new('You need to set `response` for the fixture generator! This will automatically happen with `type: :controller` or `type: :request`.', 'response') unless respond_to?(:response) + + store_frontend_fixture(response, example.description) end end @@ -29,7 +33,13 @@ module JavaScriptFixturesHelpers end end - # Public: Store a response object as fixture file + def remove_repository(project) + Gitlab::Shell.new.remove_repository(project.repository_storage, project.disk_path) + end + + private + + # Private: Store a response object as fixture file # # response - string or response object to store # fixture_file_name - file name to store the fixture in (relative to .fixture_root_path) @@ -42,12 +52,6 @@ module JavaScriptFixturesHelpers File.write(full_fixture_path, fixture) end - def remove_repository(project) - Gitlab::Shell.new.remove_repository(project.repository_storage, project.disk_path) - end - - private - # Private: Prepare a response object for use as a frontend fixture # # response - response object to prepare |