diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-20 15:07:34 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-20 15:07:34 +0000 |
commit | 8b61452138ecc511b52cd49be4ee6b8a80390c50 (patch) | |
tree | 122b817432c2a0f0e23767bd95791a89b20540c0 | |
parent | f864f8a7aafa45b0e4c04e4312f89da4b1227c0f (diff) | |
download | gitlab-ce-8b61452138ecc511b52cd49be4ee6b8a80390c50.tar.gz |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | app/models/project_services/chat_message/wiki_page_message.rb | 2 | ||||
-rw-r--r-- | app/serializers/error_tracking/detailed_error_entity.rb | 1 | ||||
-rw-r--r-- | changelogs/unreleased/119031-add-tags-to-sentry-error-api-rest.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/39140-scope-modsec-feature-flag-to-groups.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/wiki-page-message.yml | 5 | ||||
-rw-r--r-- | danger/commit_messages/Dangerfile | 14 | ||||
-rw-r--r-- | db/migrate/20191217212348_add_modsecurity_enabled_to_ingress_application.rb | 16 | ||||
-rw-r--r-- | db/schema.rb | 1 | ||||
-rw-r--r-- | doc/development/fe_guide/design_patterns.md | 6 | ||||
-rw-r--r-- | lib/gitlab/error_tracking/detailed_error.rb | 1 | ||||
-rw-r--r-- | lib/sentry/client/issue.rb | 8 | ||||
-rw-r--r-- | spec/factories/error_tracking/detailed_error.rb | 6 | ||||
-rw-r--r-- | spec/fixtures/api/schemas/error_tracking/error_detailed.json | 34 | ||||
-rw-r--r-- | spec/frontend/behaviors/bind_in_out_spec.js | 204 | ||||
-rw-r--r-- | spec/frontend/bootstrap_jquery_spec.js (renamed from spec/javascripts/bootstrap_jquery_spec.js) | 25 | ||||
-rw-r--r-- | spec/frontend/branches/branches_delete_modal_spec.js (renamed from spec/javascripts/branches/branches_delete_modal_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/breakpoints_spec.js (renamed from spec/javascripts/breakpoints_spec.js) | 6 | ||||
-rw-r--r-- | spec/frontend/diffs/components/settings_dropdown_spec.js (renamed from spec/javascripts/diffs/components/settings_dropdown_spec.js) | 14 | ||||
-rw-r--r-- | spec/frontend/droplab/constants_spec.js | 39 | ||||
-rw-r--r-- | spec/frontend/droplab/plugins/ajax_filter_spec.js (renamed from spec/javascripts/droplab/plugins/ajax_filter_spec.js) | 10 | ||||
-rw-r--r-- | spec/frontend/droplab/plugins/ajax_spec.js (renamed from spec/javascripts/droplab/plugins/ajax_spec.js) | 8 | ||||
-rw-r--r-- | spec/frontend/feature_highlight/feature_highlight_options_spec.js (renamed from spec/javascripts/feature_highlight/feature_highlight_options_spec.js) | 8 | ||||
-rw-r--r-- | spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js (renamed from spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js) | 4 | ||||
-rw-r--r-- | spec/frontend/filtered_search/dropdown_user_spec.js (renamed from spec/javascripts/filtered_search/dropdown_user_spec.js) | 18 | ||||
-rw-r--r-- | spec/frontend/frequent_items/components/frequent_items_search_input_spec.js (renamed from spec/javascripts/frequent_items/components/frequent_items_search_input_spec.js) | 10 | ||||
-rw-r--r-- | spec/frontend/gl_field_errors_spec.js (renamed from spec/javascripts/gl_field_errors_spec.js) | 62 | ||||
-rw-r--r-- | spec/frontend/gpg_badges_spec.js (renamed from spec/javascripts/gpg_badges_spec.js) | 4 | ||||
-rw-r--r-- | spec/frontend/header_spec.js (renamed from spec/javascripts/header_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/helpers/class_spec_helper_spec.js (renamed from spec/javascripts/helpers/class_spec_helper_spec.js) | 10 | ||||
-rw-r--r-- | spec/frontend/ide/components/commit_sidebar/stage_button_spec.js (renamed from spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js) | 4 | ||||
-rw-r--r-- | spec/frontend/ide/components/commit_sidebar/unstage_button_spec.js (renamed from spec/javascripts/ide/components/commit_sidebar/unstage_button_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/ide/components/jobs/detail/scroll_button_spec.js (renamed from spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/ide/stores/actions/file_spec.js (renamed from spec/javascripts/ide/stores/actions/file_spec.js) | 32 | ||||
-rw-r--r-- | spec/frontend/image_diff/helpers/init_image_diff_spec.js (renamed from spec/javascripts/image_diff/helpers/init_image_diff_spec.js) | 4 | ||||
-rw-r--r-- | spec/frontend/image_diff/init_discussion_tab_spec.js (renamed from spec/javascripts/image_diff/init_discussion_tab_spec.js) | 22 | ||||
-rw-r--r-- | spec/frontend/issue_show/components/edit_actions_spec.js (renamed from spec/javascripts/issue_show/components/edit_actions_spec.js) | 8 | ||||
-rw-r--r-- | spec/frontend/issue_show/components/fields/description_spec.js (renamed from spec/javascripts/issue_show/components/fields/description_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/issue_show/components/fields/title_spec.js (renamed from spec/javascripts/issue_show/components/fields/title_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/issue_show/index_spec.js (renamed from spec/javascripts/issue_show/index_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/jobs/components/job_log_controllers_spec.js (renamed from spec/javascripts/jobs/components/job_log_controllers_spec.js) | 8 | ||||
-rw-r--r-- | spec/frontend/namespace_select_spec.js (renamed from spec/javascripts/namespace_select_spec.js) | 10 | ||||
-rw-r--r-- | spec/frontend/new_branch_spec.js (renamed from spec/javascripts/new_branch_spec.js) | 68 | ||||
-rw-r--r-- | spec/frontend/notes/components/discussion_filter_note_spec.js (renamed from spec/javascripts/notes/components/discussion_filter_note_spec.js) | 6 | ||||
-rw-r--r-- | spec/frontend/notes/components/note_header_spec.js (renamed from spec/javascripts/notes/components/note_header_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/notes/stores/getters_spec.js (renamed from spec/javascripts/notes/stores/getters_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/notes/stores/mutation_spec.js (renamed from spec/javascripts/notes/stores/mutation_spec.js) | 4 | ||||
-rw-r--r-- | spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js (renamed from spec/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js) | 6 | ||||
-rw-r--r-- | spec/frontend/pipelines/nav_controls_spec.js (renamed from spec/javascripts/pipelines/nav_controls_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/polyfills/element_spec.js | 46 | ||||
-rw-r--r-- | spec/frontend/profile/add_ssh_key_validation_spec.js (renamed from spec/javascripts/profile/add_ssh_key_validation_spec.js) | 10 | ||||
-rw-r--r-- | spec/frontend/project_select_combo_button_spec.js | 140 | ||||
-rw-r--r-- | spec/frontend/shared/popover_spec.js (renamed from spec/javascripts/shared/popover_spec.js) | 38 | ||||
-rw-r--r-- | spec/frontend/sidebar/sidebar_store_spec.js | 168 | ||||
-rw-r--r-- | spec/frontend/syntax_highlight_spec.js (renamed from spec/javascripts/syntax_highlight_spec.js) | 26 | ||||
-rw-r--r-- | spec/frontend/task_list_spec.js (renamed from spec/javascripts/task_list_spec.js) | 30 | ||||
-rw-r--r-- | spec/frontend/version_check_image_spec.js | 42 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/gl_modal_vuex_spec.js (renamed from spec/javascripts/vue_shared/components/gl_modal_vuex_spec.js) | 10 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js (renamed from spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js) | 2 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js (renamed from spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js) | 2 | ||||
-rw-r--r-- | spec/javascripts/behaviors/bind_in_out_spec.js | 192 | ||||
-rw-r--r-- | spec/javascripts/droplab/constants_spec.js | 39 | ||||
-rw-r--r-- | spec/javascripts/polyfills/element_spec.js | 36 | ||||
-rw-r--r-- | spec/javascripts/project_select_combo_button_spec.js | 124 | ||||
-rw-r--r-- | spec/javascripts/sidebar/sidebar_store_spec.js | 162 | ||||
-rw-r--r-- | spec/javascripts/version_check_image_spec.js | 35 | ||||
-rw-r--r-- | spec/lib/sentry/client/issue_spec.rb | 4 | ||||
-rw-r--r-- | spec/models/project_services/chat_message/wiki_page_message_spec.rb | 19 |
68 files changed, 990 insertions, 855 deletions
@@ -1 +1 @@ -12.6.0-pre +12.7.0-pre diff --git a/app/models/project_services/chat_message/wiki_page_message.rb b/app/models/project_services/chat_message/wiki_page_message.rb index b605d289278..ebe7abb379f 100644 --- a/app/models/project_services/chat_message/wiki_page_message.rb +++ b/app/models/project_services/chat_message/wiki_page_message.rb @@ -14,7 +14,7 @@ module ChatMessage obj_attr = HashWithIndifferentAccess.new(obj_attr) @title = obj_attr[:title] @wiki_page_url = obj_attr[:url] - @description = obj_attr[:content] + @description = obj_attr[:message] @action = case obj_attr[:action] diff --git a/app/serializers/error_tracking/detailed_error_entity.rb b/app/serializers/error_tracking/detailed_error_entity.rb index dd0cac8e4cd..fdafa2cf203 100644 --- a/app/serializers/error_tracking/detailed_error_entity.rb +++ b/app/serializers/error_tracking/detailed_error_entity.rb @@ -21,6 +21,7 @@ module ErrorTracking :project_slug, :short_id, :status, + :tags, :title, :type, :user_count diff --git a/changelogs/unreleased/119031-add-tags-to-sentry-error-api-rest.yml b/changelogs/unreleased/119031-add-tags-to-sentry-error-api-rest.yml new file mode 100644 index 00000000000..19713a6fea2 --- /dev/null +++ b/changelogs/unreleased/119031-add-tags-to-sentry-error-api-rest.yml @@ -0,0 +1,5 @@ +--- +title: Add tags to sentry detailed error response +merge_request: 22068 +author: +type: added diff --git a/changelogs/unreleased/39140-scope-modsec-feature-flag-to-groups.yml b/changelogs/unreleased/39140-scope-modsec-feature-flag-to-groups.yml new file mode 100644 index 00000000000..54b0a8ac6db --- /dev/null +++ b/changelogs/unreleased/39140-scope-modsec-feature-flag-to-groups.yml @@ -0,0 +1,5 @@ +--- +title: Add modsecurity_enabled setting to managed ingress +merge_request: 21968 +author: +type: added diff --git a/changelogs/unreleased/wiki-page-message.yml b/changelogs/unreleased/wiki-page-message.yml new file mode 100644 index 00000000000..028c3cfd1e0 --- /dev/null +++ b/changelogs/unreleased/wiki-page-message.yml @@ -0,0 +1,5 @@ +--- +title: Include commit message instead of entire page content in Wiki chat notifications +merge_request: 21722 +author: Ville Skyttä +type: changed diff --git a/danger/commit_messages/Dangerfile b/danger/commit_messages/Dangerfile index 60bc90139ab..a7466aa6ffb 100644 --- a/danger/commit_messages/Dangerfile +++ b/danger/commit_messages/Dangerfile @@ -59,12 +59,6 @@ def subject_starts_with_capital?(subject) first_char.upcase == first_char end -def ce_upstream? - return unless gitlab_danger.ci? - - gitlab.mr_labels.any? { |label| label == 'CE upstream' } -end - def too_many_changed_lines?(commit) commit.diff_parent.stats[:total][:files] > 3 && lines_changed_in_commit(commit) >= 30 @@ -291,11 +285,11 @@ def lint_commits(commits) end end -if count_filtered_commits(git.commits) > 10 && !ce_upstream? - warn( +lint_commits(git.commits) + +if count_filtered_commits(git.commits) > 10 + fail( 'This merge request includes more than 10 commits. ' \ 'Please rebase these commits into a smaller number of commits.' ) -else - lint_commits(git.commits) end diff --git a/db/migrate/20191217212348_add_modsecurity_enabled_to_ingress_application.rb b/db/migrate/20191217212348_add_modsecurity_enabled_to_ingress_application.rb new file mode 100644 index 00000000000..2690a5762dd --- /dev/null +++ b/db/migrate/20191217212348_add_modsecurity_enabled_to_ingress_application.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddModsecurityEnabledToIngressApplication < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def up + add_column :clusters_applications_ingress, :modsecurity_enabled, :boolean + end + + def down + remove_column :clusters_applications_ingress, :modsecurity_enabled + end +end diff --git a/db/schema.rb b/db/schema.rb index dee28ea4287..0f709482884 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1163,6 +1163,7 @@ ActiveRecord::Schema.define(version: 2019_12_18_225624) do t.text "status_reason" t.string "external_ip" t.string "external_hostname" + t.boolean "modsecurity_enabled" t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true end diff --git a/doc/development/fe_guide/design_patterns.md b/doc/development/fe_guide/design_patterns.md index a7a0f39e2f3..72a7861ffcb 100644 --- a/doc/development/fe_guide/design_patterns.md +++ b/doc/development/fe_guide/design_patterns.md @@ -31,11 +31,11 @@ export default new MyThing(); export default class MyThing { constructor() { - if (!this.prototype.singleton) { + if (!MyThing.prototype.singleton) { this.init(); - this.prototype.singleton = this; + MyThing.prototype.singleton = this; } - return this.prototype.singleton; + return MyThing.prototype.singleton; } init() { diff --git a/lib/gitlab/error_tracking/detailed_error.rb b/lib/gitlab/error_tracking/detailed_error.rb index 169d6c03f12..a95e367c8b8 100644 --- a/lib/gitlab/error_tracking/detailed_error.rb +++ b/lib/gitlab/error_tracking/detailed_error.rb @@ -26,6 +26,7 @@ module Gitlab :project_slug, :short_id, :status, + :tags, :title, :type, :user_count diff --git a/lib/sentry/client/issue.rb b/lib/sentry/client/issue.rb index 08ed5392a11..28e87ab18a1 100644 --- a/lib/sentry/client/issue.rb +++ b/lib/sentry/client/issue.rb @@ -36,6 +36,7 @@ module Sentry id: issue.fetch('id'), first_seen: issue.fetch('firstSeen', nil), last_seen: issue.fetch('lastSeen', nil), + tags: extract_tags(issue), title: issue.fetch('title', nil), type: issue.fetch('type', nil), user_count: issue.fetch('userCount', nil), @@ -57,6 +58,13 @@ module Sentry last_release_short_version: issue.dig('lastRelease', 'shortVersion') ) end + + def extract_tags(issue) + { + level: issue.fetch('level', nil), + logger: issue.fetch('logger', nil) + } + end end end end diff --git a/spec/factories/error_tracking/detailed_error.rb b/spec/factories/error_tracking/detailed_error.rb index f12c327d403..b0114558bd4 100644 --- a/spec/factories/error_tracking/detailed_error.rb +++ b/spec/factories/error_tracking/detailed_error.rb @@ -18,6 +18,12 @@ FactoryBot.define do project_slug { 'project_name' } short_id { 'ID' } status { 'unresolved' } + tags do + { + level: 'error', + logger: 'rails' + } + end frequency do [ [Time.now.to_i, 10] diff --git a/spec/fixtures/api/schemas/error_tracking/error_detailed.json b/spec/fixtures/api/schemas/error_tracking/error_detailed.json index 2a1cd2c03e0..9a6797bf3c7 100644 --- a/spec/fixtures/api/schemas/error_tracking/error_detailed.json +++ b/spec/fixtures/api/schemas/error_tracking/error_detailed.json @@ -5,6 +5,7 @@ "external_base_url", "last_seen", "message", + "tags", "type", "title", "project_id", @@ -20,23 +21,38 @@ "last_release_short_version" ], "properties" : { - "id": { "type": "string"}, + "id": { "type": "string" }, "first_seen": { "type": "string", "format": "date-time" }, "last_seen": { "type": "string", "format": "date-time" }, "type": { "type": "string" }, "message": { "type": "string" }, "culprit": { "type": "string" }, - "count": { "type": "integer"}, + "count": { "type": "integer" }, "external_url": { "type": "string" }, "external_base_url": { "type": "string" }, "user_count": { "type": "integer"}, - "title": { "type": "string"}, - "project_id": { "type": "string"}, - "project_name": { "type": "string"}, - "project_slug": { "type": "string"}, - "short_id": { "type": "string"}, - "status": { "type": "string"}, - "frequency": { "type": "array"}, + "tags": { + "type": "object", + "required" : [ + "level", + "logger" + ], + "properties": { + "level": { + "type": "string" + }, + "logger": { + "type": "string" + } + } + }, + "title": { "type": "string" }, + "project_id": { "type": "string" }, + "project_name": { "type": "string" }, + "project_slug": { "type": "string" }, + "short_id": { "type": "string" }, + "status": { "type": "string" }, + "frequency": { "type": "array" }, "gitlab_issue": { "type": ["string", "null"] }, "first_release_last_commit": { "type": ["string", "null"] }, "last_release_last_commit": { "type": ["string", "null"] }, diff --git a/spec/frontend/behaviors/bind_in_out_spec.js b/spec/frontend/behaviors/bind_in_out_spec.js new file mode 100644 index 00000000000..923b6d372dd --- /dev/null +++ b/spec/frontend/behaviors/bind_in_out_spec.js @@ -0,0 +1,204 @@ +import BindInOut from '~/behaviors/bind_in_out'; +import ClassSpecHelper from '../helpers/class_spec_helper'; + +describe('BindInOut', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + + describe('constructor', () => { + beforeEach(() => { + testContext.in = {}; + testContext.out = {}; + + testContext.bindInOut = new BindInOut(testContext.in, testContext.out); + }); + + it('should set .in', () => { + expect(testContext.bindInOut.in).toBe(testContext.in); + }); + + it('should set .out', () => { + expect(testContext.bindInOut.out).toBe(testContext.out); + }); + + it('should set .eventWrapper', () => { + expect(testContext.bindInOut.eventWrapper).toEqual({}); + }); + + describe('if .in is an input', () => { + beforeEach(() => { + testContext.bindInOut = new BindInOut({ tagName: 'INPUT' }); + }); + + it('should set .eventType to keyup ', () => { + expect(testContext.bindInOut.eventType).toEqual('keyup'); + }); + }); + + describe('if .in is a textarea', () => { + beforeEach(() => { + testContext.bindInOut = new BindInOut({ tagName: 'TEXTAREA' }); + }); + + it('should set .eventType to keyup ', () => { + expect(testContext.bindInOut.eventType).toEqual('keyup'); + }); + }); + + describe('if .in is not an input or textarea', () => { + beforeEach(() => { + testContext.bindInOut = new BindInOut({ tagName: 'SELECT' }); + }); + + it('should set .eventType to change ', () => { + expect(testContext.bindInOut.eventType).toEqual('change'); + }); + }); + }); + + describe('addEvents', () => { + beforeEach(() => { + testContext.in = { + addEventListener: jest.fn(), + }; + + testContext.bindInOut = new BindInOut(testContext.in); + + testContext.addEvents = testContext.bindInOut.addEvents(); + }); + + it('should set .eventWrapper.updateOut', () => { + expect(testContext.bindInOut.eventWrapper.updateOut).toEqual(expect.any(Function)); + }); + + it('should call .addEventListener', () => { + expect(testContext.in.addEventListener).toHaveBeenCalledWith( + testContext.bindInOut.eventType, + testContext.bindInOut.eventWrapper.updateOut, + ); + }); + + it('should return the instance', () => { + expect(testContext.addEvents).toBe(testContext.bindInOut); + }); + }); + + describe('updateOut', () => { + beforeEach(() => { + testContext.in = { value: 'the-value' }; + testContext.out = { textContent: 'not-the-value' }; + + testContext.bindInOut = new BindInOut(testContext.in, testContext.out); + + testContext.updateOut = testContext.bindInOut.updateOut(); + }); + + it('should set .out.textContent to .in.value', () => { + expect(testContext.out.textContent).toBe(testContext.in.value); + }); + + it('should return the instance', () => { + expect(testContext.updateOut).toBe(testContext.bindInOut); + }); + }); + + describe('removeEvents', () => { + beforeEach(() => { + testContext.in = { + removeEventListener: jest.fn(), + }; + testContext.updateOut = () => {}; + + testContext.bindInOut = new BindInOut(testContext.in); + testContext.bindInOut.eventWrapper.updateOut = testContext.updateOut; + + testContext.removeEvents = testContext.bindInOut.removeEvents(); + }); + + it('should call .removeEventListener', () => { + expect(testContext.in.removeEventListener).toHaveBeenCalledWith( + testContext.bindInOut.eventType, + testContext.updateOut, + ); + }); + + it('should return the instance', () => { + expect(testContext.removeEvents).toBe(testContext.bindInOut); + }); + }); + + describe('initAll', () => { + beforeEach(() => { + testContext.ins = [0, 1, 2]; + testContext.instances = []; + + jest.spyOn(document, 'querySelectorAll').mockReturnValue(testContext.ins); + jest.spyOn(Array.prototype, 'map'); + jest.spyOn(BindInOut, 'init').mockImplementation(() => {}); + + testContext.initAll = BindInOut.initAll(); + }); + + ClassSpecHelper.itShouldBeAStaticMethod(BindInOut, 'initAll'); + + it('should call .querySelectorAll', () => { + expect(document.querySelectorAll).toHaveBeenCalledWith('*[data-bind-in]'); + }); + + it('should call .map', () => { + expect(Array.prototype.map).toHaveBeenCalledWith(expect.any(Function)); + }); + + it('should call .init for each element', () => { + expect(BindInOut.init.mock.calls.length).toEqual(3); + }); + + it('should return an array of instances', () => { + expect(testContext.initAll).toEqual(expect.any(Array)); + }); + }); + + describe('init', () => { + beforeEach(() => { + // eslint-disable-next-line func-names + jest.spyOn(BindInOut.prototype, 'addEvents').mockImplementation(function() { + return this; + }); + // eslint-disable-next-line func-names + jest.spyOn(BindInOut.prototype, 'updateOut').mockImplementation(function() { + return this; + }); + + testContext.init = BindInOut.init({}, {}); + }); + + ClassSpecHelper.itShouldBeAStaticMethod(BindInOut, 'init'); + + it('should call .addEvents', () => { + expect(BindInOut.prototype.addEvents).toHaveBeenCalled(); + }); + + it('should call .updateOut', () => { + expect(BindInOut.prototype.updateOut).toHaveBeenCalled(); + }); + + describe('if no anOut is provided', () => { + beforeEach(() => { + testContext.anIn = { dataset: { bindIn: 'the-data-bind-in' } }; + + jest.spyOn(document, 'querySelector').mockImplementation(() => {}); + + BindInOut.init(testContext.anIn); + }); + + it('should call .querySelector', () => { + expect(document.querySelector).toHaveBeenCalledWith( + `*[data-bind-out="${testContext.anIn.dataset.bindIn}"]`, + ); + }); + }); + }); +}); diff --git a/spec/javascripts/bootstrap_jquery_spec.js b/spec/frontend/bootstrap_jquery_spec.js index 6957cf40301..d5d592e3839 100644 --- a/spec/javascripts/bootstrap_jquery_spec.js +++ b/spec/frontend/bootstrap_jquery_spec.js @@ -1,37 +1,40 @@ import $ from 'jquery'; import '~/commons/bootstrap'; -describe('Bootstrap jQuery extensions', function() { - describe('disable', function() { - beforeEach(function() { - return setFixtures('<input type="text" />'); +describe('Bootstrap jQuery extensions', () => { + describe('disable', () => { + beforeEach(() => { + setFixtures('<input type="text" />'); }); - it('adds the disabled attribute', function() { + it('adds the disabled attribute', () => { const $input = $('input').first(); $input.disable(); expect($input).toHaveAttr('disabled', 'disabled'); }); - return it('adds the disabled class', function() { + + it('adds the disabled class', () => { const $input = $('input').first(); $input.disable(); expect($input).toHaveClass('disabled'); }); }); - return describe('enable', function() { - beforeEach(function() { - return setFixtures('<input type="text" disabled="disabled" class="disabled" />'); + + describe('enable', () => { + beforeEach(() => { + setFixtures('<input type="text" disabled="disabled" class="disabled" />'); }); - it('removes the disabled attribute', function() { + it('removes the disabled attribute', () => { const $input = $('input').first(); $input.enable(); expect($input).not.toHaveAttr('disabled'); }); - return it('removes the disabled class', function() { + + it('removes the disabled class', () => { const $input = $('input').first(); $input.enable(); diff --git a/spec/javascripts/branches/branches_delete_modal_spec.js b/spec/frontend/branches/branches_delete_modal_spec.js index b223b8e2c0a..21608feafc8 100644 --- a/spec/javascripts/branches/branches_delete_modal_spec.js +++ b/spec/frontend/branches/branches_delete_modal_spec.js @@ -15,7 +15,7 @@ describe('branches delete modal', () => { </div> `); $deleteButton = $('.js-delete-branch'); - submitSpy = jasmine.createSpy('submit').and.callFake(event => event.preventDefault()); + submitSpy = jest.fn(event => event.preventDefault()); $('#modal-delete-branch form').on('submit', submitSpy); // eslint-disable-next-line no-new new DeleteModal(); diff --git a/spec/javascripts/breakpoints_spec.js b/spec/frontend/breakpoints_spec.js index fc0d9eb907a..c9014ddd3e2 100644 --- a/spec/javascripts/breakpoints_spec.js +++ b/spec/frontend/breakpoints_spec.js @@ -5,7 +5,7 @@ describe('breakpoints', () => { const size = breakpoints[key]; it(`returns ${key} when larger than ${size}`, () => { - spyOn(bp, 'windowWidth').and.returnValue(size + 10); + jest.spyOn(bp, 'windowWidth').mockReturnValue(size + 10); expect(bp.getBreakpointSize()).toBe(key); }); @@ -13,13 +13,13 @@ describe('breakpoints', () => { describe('isDesktop', () => { it('returns true when screen size is medium', () => { - spyOn(bp, 'windowWidth').and.returnValue(breakpoints.md + 10); + jest.spyOn(bp, 'windowWidth').mockReturnValue(breakpoints.md + 10); expect(bp.isDesktop()).toBe(true); }); it('returns false when screen size is small', () => { - spyOn(bp, 'windowWidth').and.returnValue(breakpoints.sm + 10); + jest.spyOn(bp, 'windowWidth').mockReturnValue(breakpoints.sm + 10); expect(bp.isDesktop()).toBe(false); }); diff --git a/spec/javascripts/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js index 6c08474ffd2..c360f5584ca 100644 --- a/spec/javascripts/diffs/components/settings_dropdown_spec.js +++ b/spec/frontend/diffs/components/settings_dropdown_spec.js @@ -34,10 +34,10 @@ describe('Diff settiings dropdown component', () => { beforeEach(() => { actions = { - setInlineDiffViewType: jasmine.createSpy('setInlineDiffViewType'), - setParallelDiffViewType: jasmine.createSpy('setParallelDiffViewType'), - setRenderTreeList: jasmine.createSpy('setRenderTreeList'), - setShowWhitespace: jasmine.createSpy('setShowWhitespace'), + setInlineDiffViewType: jest.fn(), + setParallelDiffViewType: jest.fn(), + setRenderTreeList: jest.fn(), + setShowWhitespace: jest.fn(), }; }); @@ -51,7 +51,7 @@ describe('Diff settiings dropdown component', () => { vm.find('.js-list-view').trigger('click'); - expect(actions.setRenderTreeList).toHaveBeenCalledWith(jasmine.anything(), false, undefined); + expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false, undefined); }); it('tree view button dispatches setRenderTreeList with true', () => { @@ -59,7 +59,7 @@ describe('Diff settiings dropdown component', () => { vm.find('.js-tree-view').trigger('click'); - expect(actions.setRenderTreeList).toHaveBeenCalledWith(jasmine.anything(), true, undefined); + expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true, undefined); }); it('sets list button as active when renderTreeList is false', () => { @@ -155,7 +155,7 @@ describe('Diff settiings dropdown component', () => { checkbox.trigger('change'); expect(actions.setShowWhitespace).toHaveBeenCalledWith( - jasmine.anything(), + expect.anything(), { showWhitespace: true, pushState: true, diff --git a/spec/frontend/droplab/constants_spec.js b/spec/frontend/droplab/constants_spec.js new file mode 100644 index 00000000000..fd48228d6a2 --- /dev/null +++ b/spec/frontend/droplab/constants_spec.js @@ -0,0 +1,39 @@ +import * as constants from '~/droplab/constants'; + +describe('constants', () => { + describe('DATA_TRIGGER', () => { + it('should be `data-dropdown-trigger`', () => { + expect(constants.DATA_TRIGGER).toBe('data-dropdown-trigger'); + }); + }); + + describe('DATA_DROPDOWN', () => { + it('should be `data-dropdown`', () => { + expect(constants.DATA_DROPDOWN).toBe('data-dropdown'); + }); + }); + + describe('SELECTED_CLASS', () => { + it('should be `droplab-item-selected`', () => { + expect(constants.SELECTED_CLASS).toBe('droplab-item-selected'); + }); + }); + + describe('ACTIVE_CLASS', () => { + it('should be `droplab-item-active`', () => { + expect(constants.ACTIVE_CLASS).toBe('droplab-item-active'); + }); + }); + + describe('TEMPLATE_REGEX', () => { + it('should be a handlebars templating syntax regex', () => { + expect(constants.TEMPLATE_REGEX).toEqual(/\{\{(.+?)\}\}/g); + }); + }); + + describe('IGNORE_CLASS', () => { + it('should be `droplab-item-ignore`', () => { + expect(constants.IGNORE_CLASS).toBe('droplab-item-ignore'); + }); + }); +}); diff --git a/spec/javascripts/droplab/plugins/ajax_filter_spec.js b/spec/frontend/droplab/plugins/ajax_filter_spec.js index 5dbe50af07f..5ec0400cbc5 100644 --- a/spec/javascripts/droplab/plugins/ajax_filter_spec.js +++ b/spec/frontend/droplab/plugins/ajax_filter_spec.js @@ -28,10 +28,10 @@ describe('AjaxFilter', () => { let ajaxSpy; beforeEach(() => { - spyOn(AjaxCache, 'retrieve').and.callFake(url => ajaxSpy(url)); - spyOn(AjaxFilter, '_loadData'); + jest.spyOn(AjaxCache, 'retrieve').mockImplementation(url => ajaxSpy(url)); + jest.spyOn(AjaxFilter, '_loadData').mockImplementation(() => {}); - dummyConfig.onLoadingFinished = jasmine.createSpy('spy'); + dummyConfig.onLoadingFinished = jest.fn(); const dynamicList = document.createElement('div'); dynamicList.dataset.dynamic = true; @@ -46,7 +46,7 @@ describe('AjaxFilter', () => { AjaxFilter.trigger() .then(() => { - expect(dummyConfig.onLoadingFinished.calls.count()).toBe(1); + expect(dummyConfig.onLoadingFinished.mock.calls.length).toBe(1); }) .then(done) .catch(done.fail); @@ -63,7 +63,7 @@ describe('AjaxFilter', () => { .then(done.fail) .catch(error => { expect(error).toBe(dummyError); - expect(dummyConfig.onLoadingFinished.calls.count()).toBe(0); + expect(dummyConfig.onLoadingFinished.mock.calls.length).toBe(0); }) .then(done) .catch(done.fail); diff --git a/spec/javascripts/droplab/plugins/ajax_spec.js b/spec/frontend/droplab/plugins/ajax_spec.js index 2f492d00c0a..1d7576ce420 100644 --- a/spec/javascripts/droplab/plugins/ajax_spec.js +++ b/spec/frontend/droplab/plugins/ajax_spec.js @@ -18,23 +18,23 @@ describe('Ajax', () => { beforeEach(() => { config.preprocessing = () => processedArray; - spyOn(config, 'preprocessing').and.callFake(() => processedArray); + jest.spyOn(config, 'preprocessing').mockImplementation(() => processedArray); }); it('calls preprocessing', () => { Ajax.preprocessing(config, []); - expect(config.preprocessing.calls.count()).toBe(1); + expect(config.preprocessing.mock.calls.length).toBe(1); }); it('overrides AjaxCache', () => { - spyOn(AjaxCache, 'override').and.callFake((endpoint, results) => { + jest.spyOn(AjaxCache, 'override').mockImplementation((endpoint, results) => { expect(results).toEqual(processedArray); }); Ajax.preprocessing(config, []); - expect(AjaxCache.override.calls.count()).toBe(1); + expect(AjaxCache.override.mock.calls.length).toBe(1); }); }); }); diff --git a/spec/javascripts/feature_highlight/feature_highlight_options_spec.js b/spec/frontend/feature_highlight/feature_highlight_options_spec.js index 7f9425d8abe..cd41d1ed091 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_options_spec.js +++ b/spec/frontend/feature_highlight/feature_highlight_options_spec.js @@ -4,25 +4,25 @@ import bp from '~/breakpoints'; describe('feature highlight options', () => { describe('domContentLoaded', () => { it('should not call highlightFeatures when breakpoint is xs', () => { - spyOn(bp, 'getBreakpointSize').and.returnValue('xs'); + jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xs'); expect(domContentLoaded()).toBe(false); }); it('should not call highlightFeatures when breakpoint is sm', () => { - spyOn(bp, 'getBreakpointSize').and.returnValue('sm'); + jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('sm'); expect(domContentLoaded()).toBe(false); }); it('should not call highlightFeatures when breakpoint is md', () => { - spyOn(bp, 'getBreakpointSize').and.returnValue('md'); + jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('md'); expect(domContentLoaded()).toBe(false); }); it('should call highlightFeatures when breakpoint is lg', () => { - spyOn(bp, 'getBreakpointSize').and.returnValue('lg'); + jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('lg'); expect(domContentLoaded()).toBe(true); }); diff --git a/spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js b/spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js index d1742dcedfa..2543fb8768b 100644 --- a/spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js +++ b/spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js @@ -158,7 +158,7 @@ describe('RecentSearchesDropdownContent', () => { let onRecentSearchesItemSelectedSpy; beforeEach(() => { - onRecentSearchesItemSelectedSpy = jasmine.createSpy('spy'); + onRecentSearchesItemSelectedSpy = jest.fn(); eventHub.$on('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy); vm = createComponent(propsDataWithItems); @@ -180,7 +180,7 @@ describe('RecentSearchesDropdownContent', () => { let onRequestClearRecentSearchesSpy; beforeEach(() => { - onRequestClearRecentSearchesSpy = jasmine.createSpy('spy'); + onRequestClearRecentSearchesSpy = jest.fn(); eventHub.$on('requestClearRecentSearches', onRequestClearRecentSearchesSpy); vm = createComponent(propsDataWithItems); diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js b/spec/frontend/filtered_search/dropdown_user_spec.js index f764800fff0..8eef10290bf 100644 --- a/spec/javascripts/filtered_search/dropdown_user_spec.js +++ b/spec/frontend/filtered_search/dropdown_user_spec.js @@ -8,10 +8,10 @@ describe('Dropdown User', () => { let dropdownUser; beforeEach(() => { - spyOn(DropdownUser.prototype, 'bindEvents').and.callFake(() => {}); - spyOn(DropdownUser.prototype, 'getProjectId').and.callFake(() => {}); - spyOn(DropdownUser.prototype, 'getGroupId').and.callFake(() => {}); - spyOn(DropdownUtils, 'getSearchInput').and.callFake(() => {}); + jest.spyOn(DropdownUser.prototype, 'bindEvents').mockImplementation(() => {}); + jest.spyOn(DropdownUser.prototype, 'getProjectId').mockImplementation(() => {}); + jest.spyOn(DropdownUser.prototype, 'getGroupId').mockImplementation(() => {}); + jest.spyOn(DropdownUtils, 'getSearchInput').mockImplementation(() => {}); dropdownUser = new DropdownUser({ tokenKeys: IssuableFilteredTokenKeys, @@ -19,7 +19,7 @@ describe('Dropdown User', () => { }); it('should not return the double quote found in value', () => { - spyOn(FilteredSearchTokenizer, 'processTokens').and.returnValue({ + jest.spyOn(FilteredSearchTokenizer, 'processTokens').mockReturnValue({ lastToken: '"johnny appleseed', }); @@ -27,7 +27,7 @@ describe('Dropdown User', () => { }); it('should not return the single quote found in value', () => { - spyOn(FilteredSearchTokenizer, 'processTokens').and.returnValue({ + jest.spyOn(FilteredSearchTokenizer, 'processTokens').mockReturnValue({ lastToken: "'larry boy", }); @@ -37,9 +37,9 @@ describe('Dropdown User', () => { describe("config AjaxFilter's endpoint", () => { beforeEach(() => { - spyOn(DropdownUser.prototype, 'bindEvents').and.callFake(() => {}); - spyOn(DropdownUser.prototype, 'getProjectId').and.callFake(() => {}); - spyOn(DropdownUser.prototype, 'getGroupId').and.callFake(() => {}); + jest.spyOn(DropdownUser.prototype, 'bindEvents').mockImplementation(() => {}); + jest.spyOn(DropdownUser.prototype, 'getProjectId').mockImplementation(() => {}); + jest.spyOn(DropdownUser.prototype, 'getGroupId').mockImplementation(() => {}); }); it('should return endpoint', () => { diff --git a/spec/javascripts/frequent_items/components/frequent_items_search_input_spec.js b/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js index be11af8428f..e5f1ab21c7f 100644 --- a/spec/javascripts/frequent_items/components/frequent_items_search_input_spec.js +++ b/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js @@ -28,7 +28,7 @@ describe('FrequentItemsSearchInputComponent', () => { describe('methods', () => { describe('setFocus', () => { it('should set focus to search input', () => { - spyOn(vm.$refs.search, 'focus'); + jest.spyOn(vm.$refs.search, 'focus').mockImplementation(() => {}); vm.setFocus(); @@ -39,13 +39,13 @@ describe('FrequentItemsSearchInputComponent', () => { describe('mounted', () => { it('should listen `dropdownOpen` event', done => { - spyOn(eventHub, '$on'); + jest.spyOn(eventHub, '$on').mockImplementation(() => {}); const vmX = createComponent().vm; localVue.nextTick(() => { expect(eventHub.$on).toHaveBeenCalledWith( `${vmX.namespace}-dropdownOpen`, - jasmine.any(Function), + expect.any(Function), ); done(); }); @@ -55,7 +55,7 @@ describe('FrequentItemsSearchInputComponent', () => { describe('beforeDestroy', () => { it('should unbind event listeners on eventHub', done => { const vmX = createComponent().vm; - spyOn(eventHub, '$off'); + jest.spyOn(eventHub, '$off').mockImplementation(() => {}); vmX.$mount(); vmX.$destroy(); @@ -63,7 +63,7 @@ describe('FrequentItemsSearchInputComponent', () => { localVue.nextTick(() => { expect(eventHub.$off).toHaveBeenCalledWith( `${vmX.namespace}-dropdownOpen`, - jasmine.any(Function), + expect.any(Function), ); done(); }); diff --git a/spec/javascripts/gl_field_errors_spec.js b/spec/frontend/gl_field_errors_spec.js index 294f219d6fe..4653f519f65 100644 --- a/spec/javascripts/gl_field_errors_spec.js +++ b/spec/frontend/gl_field_errors_spec.js @@ -3,83 +3,89 @@ import $ from 'jquery'; import GlFieldErrors from '~/gl_field_errors'; -describe('GL Style Field Errors', function() { +describe('GL Style Field Errors', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + preloadFixtures('static/gl_field_errors.html'); - beforeEach(function() { + beforeEach(() => { loadFixtures('static/gl_field_errors.html'); const $form = $('form.gl-show-field-errors'); - this.$form = $form; - this.fieldErrors = new GlFieldErrors($form); + testContext.$form = $form; + testContext.fieldErrors = new GlFieldErrors($form); }); - it('should select the correct input elements', function() { - expect(this.$form).toBeDefined(); - expect(this.$form.length).toBe(1); - expect(this.fieldErrors).toBeDefined(); - const { inputs } = this.fieldErrors.state; + it('should select the correct input elements', () => { + expect(testContext.$form).toBeDefined(); + expect(testContext.$form.length).toBe(1); + expect(testContext.fieldErrors).toBeDefined(); + const { inputs } = testContext.fieldErrors.state; expect(inputs.length).toBe(4); }); - it('should ignore elements with custom error handling', function() { + it('should ignore elements with custom error handling', () => { const customErrorFlag = 'gl-field-error-ignore'; const customErrorElem = $(`.${customErrorFlag}`); expect(customErrorElem.length).toBe(1); - const customErrors = this.fieldErrors.state.inputs.filter(input => { + const customErrors = testContext.fieldErrors.state.inputs.filter(input => { return input.inputElement.hasClass(customErrorFlag); }); expect(customErrors.length).toBe(0); }); - it('should not show any errors before submit attempt', function() { - this.$form + it('should not show any errors before submit attempt', () => { + testContext.$form .find('.email') .val('not-a-valid-email') .keyup(); - this.$form + testContext.$form .find('.text-required') .val('') .keyup(); - this.$form + testContext.$form .find('.alphanumberic') .val('?---*') .keyup(); - const errorsShown = this.$form.find('.gl-field-error-outline'); + const errorsShown = testContext.$form.find('.gl-field-error-outline'); expect(errorsShown.length).toBe(0); }); - it('should show errors when input valid is submitted', function() { - this.$form + it('should show errors when input valid is submitted', () => { + testContext.$form .find('.email') .val('not-a-valid-email') .keyup(); - this.$form + testContext.$form .find('.text-required') .val('') .keyup(); - this.$form + testContext.$form .find('.alphanumberic') .val('?---*') .keyup(); - this.$form.submit(); + testContext.$form.submit(); - const errorsShown = this.$form.find('.gl-field-error-outline'); + const errorsShown = testContext.$form.find('.gl-field-error-outline'); expect(errorsShown.length).toBe(4); }); - it('should properly track validity state on input after invalid submission attempt', function() { - this.$form.submit(); + it('should properly track validity state on input after invalid submission attempt', () => { + testContext.$form.submit(); - const emailInputModel = this.fieldErrors.state.inputs[1]; + const emailInputModel = testContext.fieldErrors.state.inputs[1]; const fieldState = emailInputModel.state; const emailInputElement = emailInputModel.inputElement; @@ -124,9 +130,9 @@ describe('GL Style Field Errors', function() { expect(fieldState.valid).toBe(true); }); - it('should properly infer error messages', function() { - this.$form.submit(); - const trackedInputs = this.fieldErrors.state.inputs; + it('should properly infer error messages', () => { + testContext.$form.submit(); + const trackedInputs = testContext.fieldErrors.state.inputs; const inputHasTitle = trackedInputs[1]; const hasTitleErrorElem = inputHasTitle.inputElement.siblings('.gl-field-error'); const inputNoTitle = trackedInputs[2]; diff --git a/spec/javascripts/gpg_badges_spec.js b/spec/frontend/gpg_badges_spec.js index 4731484e02d..809cc5c88e2 100644 --- a/spec/javascripts/gpg_badges_spec.js +++ b/spec/frontend/gpg_badges_spec.js @@ -38,7 +38,7 @@ describe('GpgBadges', () => { it('does not make a request if there is no container element', done => { setFixtures(''); - spyOn(axios, 'get'); + jest.spyOn(axios, 'get').mockImplementation(() => {}); GpgBadges.fetch() .then(() => { @@ -50,7 +50,7 @@ describe('GpgBadges', () => { it('throws an error if the endpoint is missing', done => { setFixtures('<div class="js-signature-container"></div>'); - spyOn(axios, 'get'); + jest.spyOn(axios, 'get').mockImplementation(() => {}); GpgBadges.fetch() .then(() => done.fail('Expected error to be thrown')) diff --git a/spec/javascripts/header_spec.js b/spec/frontend/header_spec.js index c36d3be1b22..00b5b306d66 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/frontend/header_spec.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import initTodoToggle from '~/header'; -describe('Header', function() { +describe('Header', () => { const todosPendingCount = '.todos-count'; const fixtureTemplate = 'issues/open-issue.html'; diff --git a/spec/javascripts/helpers/class_spec_helper_spec.js b/spec/frontend/helpers/class_spec_helper_spec.js index f6268b0fb6d..533d5687bde 100644 --- a/spec/javascripts/helpers/class_spec_helper_spec.js +++ b/spec/frontend/helpers/class_spec_helper_spec.js @@ -2,7 +2,13 @@ import './class_spec_helper'; -describe('ClassSpecHelper', function() { +describe('ClassSpecHelper', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + describe('itShouldBeAStaticMethod', () => { beforeEach(() => { class TestClass { @@ -12,7 +18,7 @@ describe('ClassSpecHelper', function() { static staticMethod() {} } - this.TestClass = TestClass; + testContext.TestClass = TestClass; }); ClassSpecHelper.itShouldBeAStaticMethod(ClassSpecHelper, 'itShouldBeAStaticMethod'); diff --git a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js b/spec/frontend/ide/components/commit_sidebar/stage_button_spec.js index e09ccbe2a63..b59de4dac0e 100644 --- a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js +++ b/spec/frontend/ide/components/commit_sidebar/stage_button_spec.js @@ -16,8 +16,8 @@ describe('IDE stage file button', () => { path: f.path, }); - spyOn(vm, 'stageChange'); - spyOn(vm, 'discardFileChanges'); + jest.spyOn(vm, 'stageChange').mockImplementation(() => {}); + jest.spyOn(vm, 'discardFileChanges').mockImplementation(() => {}); vm.$mount(); }); diff --git a/spec/javascripts/ide/components/commit_sidebar/unstage_button_spec.js b/spec/frontend/ide/components/commit_sidebar/unstage_button_spec.js index 917bbb9fb46..53b53c8c815 100644 --- a/spec/javascripts/ide/components/commit_sidebar/unstage_button_spec.js +++ b/spec/frontend/ide/components/commit_sidebar/unstage_button_spec.js @@ -16,7 +16,7 @@ describe('IDE unstage file button', () => { path: f.path, }); - spyOn(vm, 'unstageChange'); + jest.spyOn(vm, 'unstageChange').mockImplementation(() => {}); vm.$mount(); }); diff --git a/spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js b/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js index fff382a107f..096851a5401 100644 --- a/spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js +++ b/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js @@ -40,7 +40,7 @@ describe('IDE job log scroll button', () => { }); it('emits click event on click', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.btn-scroll').click(); diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js index 03d1125c23a..283ea266821 100644 --- a/spec/javascripts/ide/stores/actions/file_spec.js +++ b/spec/frontend/ide/stores/actions/file_spec.js @@ -24,7 +24,7 @@ describe('IDE store file actions', () => { relative_url_root: RELATIVE_URL_ROOT, }; - spyOn(router, 'push'); + jest.spyOn(router, 'push').mockImplementation(() => {}); }); afterEach(() => { @@ -117,7 +117,7 @@ describe('IDE store file actions', () => { let oldScrollToTab; beforeEach(() => { - scrollToTabSpy = jasmine.createSpy('scrollToTab'); + scrollToTabSpy = jest.fn(); oldScrollToTab = store._actions.scrollToTab; // eslint-disable-line store._actions.scrollToTab = [scrollToTabSpy]; // eslint-disable-line @@ -131,7 +131,7 @@ describe('IDE store file actions', () => { }); it('calls scrollToTab', () => { - const dispatch = jasmine.createSpy(); + const dispatch = jest.fn(); actions.setFileActive( { commit() {}, state: store.state, getters: store.getters, dispatch }, @@ -142,7 +142,7 @@ describe('IDE store file actions', () => { }); it('commits SET_FILE_ACTIVE', () => { - const commit = jasmine.createSpy(); + const commit = jest.fn(); actions.setFileActive( { commit, state: store.state, getters: store.getters, dispatch() {} }, @@ -161,7 +161,7 @@ describe('IDE store file actions', () => { localFile.active = true; store.state.openFiles.push(localFile); - const commit = jasmine.createSpy(); + const commit = jest.fn(); actions.setFileActive( { commit, state: store.state, getters: store.getters, dispatch() {} }, @@ -179,7 +179,7 @@ describe('IDE store file actions', () => { let localFile; beforeEach(() => { - spyOn(service, 'getFileData').and.callThrough(); + jest.spyOn(service, 'getFileData'); localFile = file(`newCreate-${Math.random()}`); store.state.entries[localFile.path] = localFile; @@ -329,7 +329,7 @@ describe('IDE store file actions', () => { }); it('dispatches error action', done => { - const dispatch = jasmine.createSpy('dispatch'); + const dispatch = jest.fn(); actions .getFileData( @@ -339,7 +339,7 @@ describe('IDE store file actions', () => { .then(() => { expect(dispatch).toHaveBeenCalledWith('setErrorMessage', { text: 'An error occurred whilst loading the file.', - action: jasmine.any(Function), + action: expect.any(Function), actionText: 'Please try again', actionPayload: { path: localFile.path, @@ -358,7 +358,7 @@ describe('IDE store file actions', () => { let tmpFile; beforeEach(() => { - spyOn(service, 'getRawFileData').and.callThrough(); + jest.spyOn(service, 'getRawFileData'); tmpFile = file('tmpFile'); store.state.entries[tmpFile.path] = tmpFile; @@ -392,7 +392,7 @@ describe('IDE store file actions', () => { }); it('calls also getBaseRawFileData service method', done => { - spyOn(service, 'getBaseRawFileData').and.returnValue(Promise.resolve('baseraw')); + jest.spyOn(service, 'getBaseRawFileData').mockReturnValue(Promise.resolve('baseraw')); store.state.currentProjectId = 'gitlab-org/gitlab-ce'; store.state.currentMergeRequestId = '1'; @@ -443,7 +443,7 @@ describe('IDE store file actions', () => { }); it('dispatches error action', done => { - const dispatch = jasmine.createSpy('dispatch'); + const dispatch = jest.fn(); actions .getRawFileData({ state: store.state, commit() {}, dispatch }, { path: tmpFile.path }) @@ -451,7 +451,7 @@ describe('IDE store file actions', () => { .catch(() => { expect(dispatch).toHaveBeenCalledWith('setErrorMessage', { text: 'An error occurred whilst loading the file content.', - action: jasmine.any(Function), + action: expect.any(Function), actionText: 'Please try again', actionPayload: { path: tmpFile.path, @@ -575,8 +575,8 @@ describe('IDE store file actions', () => { let tmpFile; beforeEach(() => { - spyOn(eventHub, '$on'); - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$on').mockImplementation(() => {}); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); tmpFile = file(); tmpFile.content = 'testing'; @@ -756,7 +756,7 @@ describe('IDE store file actions', () => { let f; beforeEach(() => { - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); f = { ...file('pendingFile'), @@ -789,7 +789,7 @@ describe('IDE store file actions', () => { describe('triggerFilesChange', () => { beforeEach(() => { - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); }); it('emits event that files have changed', done => { diff --git a/spec/javascripts/image_diff/helpers/init_image_diff_spec.js b/spec/frontend/image_diff/helpers/init_image_diff_spec.js index ba501d58965..dc872ace265 100644 --- a/spec/javascripts/image_diff/helpers/init_image_diff_spec.js +++ b/spec/frontend/image_diff/helpers/init_image_diff_spec.js @@ -14,8 +14,8 @@ describe('initImageDiff', () => { <div class="diff-file"></div> `; - spyOn(ReplacedImageDiff.prototype, 'init').and.callFake(() => {}); - spyOn(ImageDiff.prototype, 'init').and.callFake(() => {}); + jest.spyOn(ReplacedImageDiff.prototype, 'init').mockImplementation(() => {}); + jest.spyOn(ImageDiff.prototype, 'init').mockImplementation(() => {}); }); afterEach(() => { diff --git a/spec/javascripts/image_diff/init_discussion_tab_spec.js b/spec/frontend/image_diff/init_discussion_tab_spec.js index 5eb87e1df25..f459fdf5a08 100644 --- a/spec/javascripts/image_diff/init_discussion_tab_spec.js +++ b/spec/frontend/image_diff/init_discussion_tab_spec.js @@ -12,29 +12,31 @@ describe('initDiscussionTab', () => { }); it('should pass canCreateNote as false to initImageDiff', done => { - spyOn(initImageDiffHelper, 'initImageDiff').and.callFake((diffFileEl, canCreateNote) => { - expect(canCreateNote).toEqual(false); - done(); - }); + jest + .spyOn(initImageDiffHelper, 'initImageDiff') + .mockImplementation((diffFileEl, canCreateNote) => { + expect(canCreateNote).toEqual(false); + done(); + }); initDiscussionTab(); }); it('should pass renderCommentBadge as true to initImageDiff', done => { - spyOn(initImageDiffHelper, 'initImageDiff').and.callFake( - (diffFileEl, canCreateNote, renderCommentBadge) => { + jest + .spyOn(initImageDiffHelper, 'initImageDiff') + .mockImplementation((diffFileEl, canCreateNote, renderCommentBadge) => { expect(renderCommentBadge).toEqual(true); done(); - }, - ); + }); initDiscussionTab(); }); it('should call initImageDiff for each diffFileEls', () => { - spyOn(initImageDiffHelper, 'initImageDiff').and.callFake(() => {}); + jest.spyOn(initImageDiffHelper, 'initImageDiff').mockImplementation(() => {}); initDiscussionTab(); - expect(initImageDiffHelper.initImageDiff.calls.count()).toEqual(2); + expect(initImageDiffHelper.initImageDiff.mock.calls.length).toEqual(2); }); }); diff --git a/spec/javascripts/issue_show/components/edit_actions_spec.js b/spec/frontend/issue_show/components/edit_actions_spec.js index 2ab74ae4e10..b0c1894058e 100644 --- a/spec/javascripts/issue_show/components/edit_actions_spec.js +++ b/spec/frontend/issue_show/components/edit_actions_spec.js @@ -15,7 +15,7 @@ describe('Edit Actions components', () => { }); store.formState.title = 'test'; - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); vm = new Component({ propsData: { @@ -101,14 +101,14 @@ describe('Edit Actions components', () => { describe('deleteIssuable', () => { it('sends delete.issuable event when clicking save button', () => { - spyOn(window, 'confirm').and.returnValue(true); + jest.spyOn(window, 'confirm').mockReturnValue(true); vm.$el.querySelector('.btn-danger').click(); expect(eventHub.$emit).toHaveBeenCalledWith('delete.issuable', { destroy_confirm: true }); }); it('shows loading icon after clicking delete button', done => { - spyOn(window, 'confirm').and.returnValue(true); + jest.spyOn(window, 'confirm').mockReturnValue(true); vm.$el.querySelector('.btn-danger').click(); Vue.nextTick(() => { @@ -119,7 +119,7 @@ describe('Edit Actions components', () => { }); it('does no actions when confirm is false', done => { - spyOn(window, 'confirm').and.returnValue(false); + jest.spyOn(window, 'confirm').mockReturnValue(false); vm.$el.querySelector('.btn-danger').click(); Vue.nextTick(() => { diff --git a/spec/javascripts/issue_show/components/fields/description_spec.js b/spec/frontend/issue_show/components/fields/description_spec.js index f5f87a6bfbf..8ea326ad1ee 100644 --- a/spec/javascripts/issue_show/components/fields/description_spec.js +++ b/spec/frontend/issue_show/components/fields/description_spec.js @@ -20,7 +20,7 @@ describe('Description field component', () => { document.body.appendChild(el); - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); vm = new Component({ el, diff --git a/spec/javascripts/issue_show/components/fields/title_spec.js b/spec/frontend/issue_show/components/fields/title_spec.js index 62dff983250..99e8658b89f 100644 --- a/spec/javascripts/issue_show/components/fields/title_spec.js +++ b/spec/frontend/issue_show/components/fields/title_spec.js @@ -17,7 +17,7 @@ describe('Title field component', () => { }); store.formState.title = 'test'; - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); vm = new Component({ propsData: { diff --git a/spec/javascripts/issue_show/index_spec.js b/spec/frontend/issue_show/index_spec.js index fa0b426c06c..e80d1b83c11 100644 --- a/spec/javascripts/issue_show/index_spec.js +++ b/spec/frontend/issue_show/index_spec.js @@ -10,7 +10,7 @@ describe('Issue show index', () => { }); document.body.appendChild(d); - const alertSpy = spyOn(window, 'alert'); + const alertSpy = jest.spyOn(window, 'alert'); initIssueableApp(); expect(alertSpy).not.toHaveBeenCalled(); diff --git a/spec/javascripts/jobs/components/job_log_controllers_spec.js b/spec/frontend/jobs/components/job_log_controllers_spec.js index d527c6708fc..04f20811601 100644 --- a/spec/javascripts/jobs/components/job_log_controllers_spec.js +++ b/spec/frontend/jobs/components/job_log_controllers_spec.js @@ -100,7 +100,7 @@ describe('Job log controllers', () => { }); it('emits scrollJobLogTop event on click', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.js-scroll-top').click(); expect(vm.$emit).toHaveBeenCalledWith('scrollJobLogTop'); @@ -127,7 +127,7 @@ describe('Job log controllers', () => { }); it('does not emit scrollJobLogTop event on click', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.js-scroll-top').click(); expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogTop'); @@ -146,7 +146,7 @@ describe('Job log controllers', () => { }); it('emits scrollJobLogBottom event on click', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.js-scroll-bottom').click(); expect(vm.$emit).toHaveBeenCalledWith('scrollJobLogBottom'); @@ -173,7 +173,7 @@ describe('Job log controllers', () => { }); it('does not emit scrollJobLogBottom event on click', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.js-scroll-bottom').click(); expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogBottom'); diff --git a/spec/javascripts/namespace_select_spec.js b/spec/frontend/namespace_select_spec.js index 07b82ce721e..399fa950769 100644 --- a/spec/javascripts/namespace_select_spec.js +++ b/spec/frontend/namespace_select_spec.js @@ -3,7 +3,7 @@ import NamespaceSelect from '~/namespace_select'; describe('NamespaceSelect', () => { beforeEach(() => { - spyOn($.fn, 'glDropdown'); + jest.spyOn($.fn, 'glDropdown').mockImplementation(() => {}); }); it('initializes glDropdown', () => { @@ -22,12 +22,12 @@ describe('NamespaceSelect', () => { const dropdown = document.createElement('div'); // eslint-disable-next-line no-new new NamespaceSelect({ dropdown }); - [glDropdownOptions] = $.fn.glDropdown.calls.argsFor(0); + [[glDropdownOptions]] = $.fn.glDropdown.mock.calls; }); it('prevents click events', () => { const dummyEvent = new Event('dummy'); - spyOn(dummyEvent, 'preventDefault'); + jest.spyOn(dummyEvent, 'preventDefault').mockImplementation(() => {}); glDropdownOptions.clicked({ e: dummyEvent }); @@ -43,12 +43,12 @@ describe('NamespaceSelect', () => { dropdown.dataset.isFilter = 'true'; // eslint-disable-next-line no-new new NamespaceSelect({ dropdown }); - [glDropdownOptions] = $.fn.glDropdown.calls.argsFor(0); + [[glDropdownOptions]] = $.fn.glDropdown.mock.calls; }); it('does not prevent click events', () => { const dummyEvent = new Event('dummy'); - spyOn(dummyEvent, 'preventDefault'); + jest.spyOn(dummyEvent, 'preventDefault').mockImplementation(() => {}); glDropdownOptions.clicked({ e: dummyEvent }); diff --git a/spec/javascripts/new_branch_spec.js b/spec/frontend/new_branch_spec.js index 4e3140ce4f1..cff7ec1a9ee 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/frontend/new_branch_spec.js @@ -1,8 +1,14 @@ import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; -describe('Branch', function() { - describe('create a new branch', function() { +describe('Branch', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + + describe('create a new branch', () => { preloadFixtures('branches/new_branch.html'); function fillNameWith(value) { @@ -15,30 +21,28 @@ describe('Branch', function() { expect($('.js-branch-name-error span').text()).toEqual(error); } - beforeEach(function() { + beforeEach(() => { loadFixtures('branches/new_branch.html'); - $('form').on('submit', function(e) { - return e.preventDefault(); - }); - this.form = new NewBranchForm($('.js-create-branch-form'), []); + $('form').on('submit', e => e.preventDefault()); + testContext.form = new NewBranchForm($('.js-create-branch-form'), []); }); - it("can't start with a dot", function() { + it("can't start with a dot", () => { fillNameWith('.foo'); expectToHaveError("can't start with '.'"); }); - it("can't start with a slash", function() { + it("can't start with a slash", () => { fillNameWith('/foo'); expectToHaveError("can't start with '/'"); }); - it("can't have two consecutive dots", function() { + it("can't have two consecutive dots", () => { fillNameWith('foo..bar'); expectToHaveError("can't contain '..'"); }); - it("can't have spaces anywhere", function() { + it("can't have spaces anywhere", () => { fillNameWith(' foo'); expectToHaveError("can't contain spaces"); fillNameWith('foo bar'); @@ -47,7 +51,7 @@ describe('Branch', function() { expectToHaveError("can't contain spaces"); }); - it("can't have ~ anywhere", function() { + it("can't have ~ anywhere", () => { fillNameWith('~foo'); expectToHaveError("can't contain '~'"); fillNameWith('foo~bar'); @@ -56,7 +60,7 @@ describe('Branch', function() { expectToHaveError("can't contain '~'"); }); - it("can't have tilde anwhere", function() { + it("can't have tilde anwhere", () => { fillNameWith('~foo'); expectToHaveError("can't contain '~'"); fillNameWith('foo~bar'); @@ -65,7 +69,7 @@ describe('Branch', function() { expectToHaveError("can't contain '~'"); }); - it("can't have caret anywhere", function() { + it("can't have caret anywhere", () => { fillNameWith('^foo'); expectToHaveError("can't contain '^'"); fillNameWith('foo^bar'); @@ -74,7 +78,7 @@ describe('Branch', function() { expectToHaveError("can't contain '^'"); }); - it("can't have : anywhere", function() { + it("can't have : anywhere", () => { fillNameWith(':foo'); expectToHaveError("can't contain ':'"); fillNameWith('foo:bar'); @@ -83,7 +87,7 @@ describe('Branch', function() { expectToHaveError("can't contain ':'"); }); - it("can't have question mark anywhere", function() { + it("can't have question mark anywhere", () => { fillNameWith('?foo'); expectToHaveError("can't contain '?'"); fillNameWith('foo?bar'); @@ -92,7 +96,7 @@ describe('Branch', function() { expectToHaveError("can't contain '?'"); }); - it("can't have asterisk anywhere", function() { + it("can't have asterisk anywhere", () => { fillNameWith('*foo'); expectToHaveError("can't contain '*'"); fillNameWith('foo*bar'); @@ -101,7 +105,7 @@ describe('Branch', function() { expectToHaveError("can't contain '*'"); }); - it("can't have open bracket anywhere", function() { + it("can't have open bracket anywhere", () => { fillNameWith('[foo'); expectToHaveError("can't contain '['"); fillNameWith('foo[bar'); @@ -110,7 +114,7 @@ describe('Branch', function() { expectToHaveError("can't contain '['"); }); - it("can't have a backslash anywhere", function() { + it("can't have a backslash anywhere", () => { fillNameWith('\\foo'); expectToHaveError("can't contain '\\'"); fillNameWith('foo\\bar'); @@ -119,7 +123,7 @@ describe('Branch', function() { expectToHaveError("can't contain '\\'"); }); - it("can't contain a sequence @{ anywhere", function() { + it("can't contain a sequence @{ anywhere", () => { fillNameWith('@{foo'); expectToHaveError("can't contain '@{'"); fillNameWith('foo@{bar'); @@ -128,42 +132,42 @@ describe('Branch', function() { expectToHaveError("can't contain '@{'"); }); - it("can't have consecutive slashes", function() { + it("can't have consecutive slashes", () => { fillNameWith('foo//bar'); expectToHaveError("can't contain consecutive slashes"); }); - it("can't end with a slash", function() { + it("can't end with a slash", () => { fillNameWith('foo/'); expectToHaveError("can't end in '/'"); }); - it("can't end with a dot", function() { + it("can't end with a dot", () => { fillNameWith('foo.'); expectToHaveError("can't end in '.'"); }); - it("can't end with .lock", function() { + it("can't end with .lock", () => { fillNameWith('foo.lock'); expectToHaveError("can't end in '.lock'"); }); - it("can't be the single character @", function() { + it("can't be the single character @", () => { fillNameWith('@'); expectToHaveError("can't be '@'"); }); - it('concatenates all error messages', function() { + it('concatenates all error messages', () => { fillNameWith('/foo bar?~.'); expectToHaveError("can't start with '/', can't contain spaces, '?', '~', can't end in '.'"); }); - it("doesn't duplicate error messages", function() { + it("doesn't duplicate error messages", () => { fillNameWith('?foo?bar?zoo?'); expectToHaveError("can't contain '?'"); }); - it('removes the error message when is a valid name', function() { + it('removes the error message when is a valid name', () => { fillNameWith('foo?bar'); expect($('.js-branch-name-error span').length).toEqual(1); @@ -172,25 +176,25 @@ describe('Branch', function() { expect($('.js-branch-name-error span').length).toEqual(0); }); - it('can have dashes anywhere', function() { + it('can have dashes anywhere', () => { fillNameWith('-foo-bar-zoo-'); expect($('.js-branch-name-error span').length).toEqual(0); }); - it('can have underscores anywhere', function() { + it('can have underscores anywhere', () => { fillNameWith('_foo_bar_zoo_'); expect($('.js-branch-name-error span').length).toEqual(0); }); - it('can have numbers anywhere', function() { + it('can have numbers anywhere', () => { fillNameWith('1foo2bar3zoo4'); expect($('.js-branch-name-error span').length).toEqual(0); }); - it('can be only letters', function() { + it('can be only letters', () => { fillNameWith('foo'); expect($('.js-branch-name-error span').length).toEqual(0); diff --git a/spec/javascripts/notes/components/discussion_filter_note_spec.js b/spec/frontend/notes/components/discussion_filter_note_spec.js index 52d2e7ce947..6b5f42a84e8 100644 --- a/spec/javascripts/notes/components/discussion_filter_note_spec.js +++ b/spec/frontend/notes/components/discussion_filter_note_spec.js @@ -34,7 +34,7 @@ describe('DiscussionFilterNote component', () => { describe('methods', () => { describe('selectFilter', () => { it('emits `dropdownSelect` event on `eventHub` with provided param', () => { - spyOn(eventHub, '$emit'); + jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); vm.selectFilter(1); @@ -74,7 +74,7 @@ describe('DiscussionFilterNote component', () => { it('clicking `Show all activity` button calls `selectFilter("all")` method', () => { const showAllBtn = vm.$el.querySelector('.discussion-filter-actions button:first-child'); - spyOn(vm, 'selectFilter'); + jest.spyOn(vm, 'selectFilter').mockImplementation(() => {}); showAllBtn.dispatchEvent(new Event('click')); @@ -83,7 +83,7 @@ describe('DiscussionFilterNote component', () => { it('clicking `Show comments only` button calls `selectFilter("comments")` method', () => { const showAllBtn = vm.$el.querySelector('.discussion-filter-actions button:last-child'); - spyOn(vm, 'selectFilter'); + jest.spyOn(vm, 'selectFilter').mockImplementation(() => {}); showAllBtn.dispatchEvent(new Event('click')); diff --git a/spec/javascripts/notes/components/note_header_spec.js b/spec/frontend/notes/components/note_header_spec.js index 6d1a7ef370f..9b432387654 100644 --- a/spec/javascripts/notes/components/note_header_spec.js +++ b/spec/frontend/notes/components/note_header_spec.js @@ -90,7 +90,7 @@ describe('note_header component', () => { }); it('emits toggle event on click', done => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.js-vue-toggle-button').click(); diff --git a/spec/javascripts/notes/stores/getters_spec.js b/spec/frontend/notes/stores/getters_spec.js index d69f469c7c7..83417bd70ef 100644 --- a/spec/javascripts/notes/stores/getters_spec.js +++ b/spec/frontend/notes/stores/getters_spec.js @@ -327,7 +327,7 @@ describe('Getters Notes Store', () => { beforeEach(() => { neighbor = {}; - findUnresolvedDiscussionIdNeighbor = jasmine.createSpy().and.returnValue(neighbor); + findUnresolvedDiscussionIdNeighbor = jest.fn(() => neighbor); localGetters = { findUnresolvedDiscussionIdNeighbor }; }); diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/frontend/notes/stores/mutation_spec.js index ade4725dd68..49debe348e2 100644 --- a/spec/javascripts/notes/stores/mutation_spec.js +++ b/spec/frontend/notes/stores/mutation_spec.js @@ -498,7 +498,7 @@ describe('Notes Store mutations', () => { mutations.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS(state); expect(state).toEqual( - jasmine.objectContaining({ + expect.objectContaining({ resolvableDiscussionsCount: 1, unresolvedDiscussionsCount: 1, hasUnresolvedDiscussions: false, @@ -535,7 +535,7 @@ describe('Notes Store mutations', () => { mutations.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS(state); expect(state).toEqual( - jasmine.objectContaining({ + expect.objectContaining({ resolvableDiscussionsCount: 4, unresolvedDiscussionsCount: 2, hasUnresolvedDiscussions: true, diff --git a/spec/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js index 5f4dba5ecb9..8917251d285 100644 --- a/spec/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js +++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js @@ -6,7 +6,7 @@ import TimezoneDropdown, { findTimezoneByIdentifier, } from '~/pages/projects/pipeline_schedules/shared/components/timezone_dropdown'; -describe('Timezone Dropdown', function() { +describe('Timezone Dropdown', () => { preloadFixtures('pipeline_schedules/edit.html'); let $inputEl = null; @@ -81,7 +81,7 @@ describe('Timezone Dropdown', function() { }); it('will call a provided handler when a new timezone is selected', () => { - const onSelectTimezone = jasmine.createSpy('onSelectTimezoneMock'); + const onSelectTimezone = jest.fn(); // eslint-disable-next-line no-new new TimezoneDropdown({ $inputEl, @@ -111,7 +111,7 @@ describe('Timezone Dropdown', function() { }); it('will call a provided `displayFormat` handler to format the dropdown value', () => { - const displayFormat = jasmine.createSpy('displayFormat'); + const displayFormat = jest.fn(); // eslint-disable-next-line no-new new TimezoneDropdown({ $inputEl, diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/frontend/pipelines/nav_controls_spec.js index 7806cdf1477..6d28da0ea2a 100644 --- a/spec/javascripts/pipelines/nav_controls_spec.js +++ b/spec/frontend/pipelines/nav_controls_spec.js @@ -75,7 +75,7 @@ describe('Pipelines Nav Controls', () => { }); it('should emit postAction event when reset runner cache button is clicked', () => { - spyOn(component, '$emit'); + jest.spyOn(component, '$emit').mockImplementation(() => {}); component.$el.querySelector('.js-clear-cache').click(); diff --git a/spec/frontend/polyfills/element_spec.js b/spec/frontend/polyfills/element_spec.js new file mode 100644 index 00000000000..64ce248ca44 --- /dev/null +++ b/spec/frontend/polyfills/element_spec.js @@ -0,0 +1,46 @@ +import '~/commons/polyfills/element'; + +describe('Element polyfills', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + + beforeEach(() => { + testContext.element = document.createElement('ul'); + }); + + describe('matches', () => { + it('returns true if element matches the selector', () => { + expect(testContext.element.matches('ul')).toBeTruthy(); + }); + + it("returns false if element doesn't match the selector", () => { + expect(testContext.element.matches('.not-an-element')).toBeFalsy(); + }); + }); + + describe('closest', () => { + beforeEach(() => { + testContext.childElement = document.createElement('li'); + testContext.element.appendChild(testContext.childElement); + }); + + it('returns the closest parent that matches the selector', () => { + expect(testContext.childElement.closest('ul').toString()).toBe( + testContext.element.toString(), + ); + }); + + it('returns itself if it matches the selector', () => { + expect(testContext.childElement.closest('li').toString()).toBe( + testContext.childElement.toString(), + ); + }); + + it('returns undefined if nothing matches the selector', () => { + expect(testContext.childElement.closest('.no-an-element')).toBeFalsy(); + }); + }); +}); diff --git a/spec/javascripts/profile/add_ssh_key_validation_spec.js b/spec/frontend/profile/add_ssh_key_validation_spec.js index c71a2885acc..1fec864599c 100644 --- a/spec/javascripts/profile/add_ssh_key_validation_spec.js +++ b/spec/frontend/profile/add_ssh_key_validation_spec.js @@ -4,16 +4,18 @@ describe('AddSshKeyValidation', () => { describe('submit', () => { it('returns true if isValid is true', () => { const addSshKeyValidation = new AddSshKeyValidation({}); - spyOn(AddSshKeyValidation, 'isPublicKey').and.returnValue(true); + jest.spyOn(AddSshKeyValidation, 'isPublicKey').mockReturnValue(true); expect(addSshKeyValidation.submit()).toBeTruthy(); }); it('calls preventDefault and toggleWarning if isValid is false', () => { const addSshKeyValidation = new AddSshKeyValidation({}); - const event = jasmine.createSpyObj('event', ['preventDefault']); - spyOn(AddSshKeyValidation, 'isPublicKey').and.returnValue(false); - spyOn(addSshKeyValidation, 'toggleWarning'); + const event = { + preventDefault: jest.fn(), + }; + jest.spyOn(AddSshKeyValidation, 'isPublicKey').mockReturnValue(false); + jest.spyOn(addSshKeyValidation, 'toggleWarning').mockImplementation(() => {}); addSshKeyValidation.submit(event); diff --git a/spec/frontend/project_select_combo_button_spec.js b/spec/frontend/project_select_combo_button_spec.js new file mode 100644 index 00000000000..c47db71b4ac --- /dev/null +++ b/spec/frontend/project_select_combo_button_spec.js @@ -0,0 +1,140 @@ +import $ from 'jquery'; +import ProjectSelectComboButton from '~/project_select_combo_button'; + +const fixturePath = 'static/project_select_combo_button.html'; + +describe('Project Select Combo Button', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + + preloadFixtures(fixturePath); + + beforeEach(() => { + testContext.defaults = { + label: 'Select project to create issue', + groupId: 12345, + projectMeta: { + name: 'My Cool Project', + url: 'http://mycoolproject.com', + }, + newProjectMeta: { + name: 'My Other Cool Project', + url: 'http://myothercoolproject.com', + }, + localStorageKey: 'group-12345-new-issue-recent-project', + relativePath: 'issues/new', + }; + + loadFixtures(fixturePath); + + testContext.newItemBtn = document.querySelector('.new-project-item-link'); + testContext.projectSelectInput = document.querySelector('.project-item-select'); + }); + + describe('on page load when localStorage is empty', () => { + beforeEach(() => { + testContext.comboButton = new ProjectSelectComboButton(testContext.projectSelectInput); + }); + + it('newItemBtn href is null', () => { + expect(testContext.newItemBtn.getAttribute('href')).toBe(''); + }); + + it('newItemBtn text is the plain default label', () => { + expect(testContext.newItemBtn.textContent).toBe(testContext.defaults.label); + }); + }); + + describe('on page load when localStorage is filled', () => { + beforeEach(() => { + window.localStorage.setItem( + testContext.defaults.localStorageKey, + JSON.stringify(testContext.defaults.projectMeta), + ); + testContext.comboButton = new ProjectSelectComboButton(testContext.projectSelectInput); + }); + + it('newItemBtn href is correctly set', () => { + expect(testContext.newItemBtn.getAttribute('href')).toBe( + testContext.defaults.projectMeta.url, + ); + }); + + it('newItemBtn text is the cached label', () => { + expect(testContext.newItemBtn.textContent).toBe( + `New issue in ${testContext.defaults.projectMeta.name}`, + ); + }); + + afterEach(() => { + window.localStorage.clear(); + }); + }); + + describe('after selecting a new project', () => { + beforeEach(() => { + testContext.comboButton = new ProjectSelectComboButton(testContext.projectSelectInput); + + // mock the effect of selecting an item from the projects dropdown (select2) + $('.project-item-select') + .val(JSON.stringify(testContext.defaults.newProjectMeta)) + .trigger('change'); + }); + + it('newItemBtn href is correctly set', () => { + expect(testContext.newItemBtn.getAttribute('href')).toBe( + 'http://myothercoolproject.com/issues/new', + ); + }); + + it('newItemBtn text is the selected project label', () => { + expect(testContext.newItemBtn.textContent).toBe( + `New issue in ${testContext.defaults.newProjectMeta.name}`, + ); + }); + + afterEach(() => { + window.localStorage.clear(); + }); + }); + + describe('deriveTextVariants', () => { + beforeEach(() => { + testContext.mockExecutionContext = { + resourceType: '', + resourceLabel: '', + }; + + testContext.comboButton = new ProjectSelectComboButton(testContext.projectSelectInput); + + testContext.method = testContext.comboButton.deriveTextVariants.bind( + testContext.mockExecutionContext, + ); + }); + + it('correctly derives test variants for merge requests', () => { + testContext.mockExecutionContext.resourceType = 'merge_requests'; + testContext.mockExecutionContext.resourceLabel = 'New merge request'; + + const returnedVariants = testContext.method(); + + expect(returnedVariants.localStorageItemType).toBe('new-merge-request'); + expect(returnedVariants.defaultTextPrefix).toBe('New merge request'); + expect(returnedVariants.presetTextSuffix).toBe('merge request'); + }); + + it('correctly derives text variants for issues', () => { + testContext.mockExecutionContext.resourceType = 'issues'; + testContext.mockExecutionContext.resourceLabel = 'New issue'; + + const returnedVariants = testContext.method(); + + expect(returnedVariants.localStorageItemType).toBe('new-issue'); + expect(returnedVariants.defaultTextPrefix).toBe('New issue'); + expect(returnedVariants.presetTextSuffix).toBe('issue'); + }); + }); +}); diff --git a/spec/javascripts/shared/popover_spec.js b/spec/frontend/shared/popover_spec.js index cc2b2014d38..bbde936185e 100644 --- a/spec/javascripts/shared/popover_spec.js +++ b/spec/frontend/shared/popover_spec.js @@ -29,7 +29,7 @@ describe('popover', () => { toggleClass: () => {}, }; - spyOn(context, 'popover').and.callFake(method => { + jest.spyOn(context, 'popover').mockImplementation(method => { expect(method).toEqual('show'); done(); }); @@ -44,7 +44,7 @@ describe('popover', () => { toggleClass: () => {}, }; - spyOn(context, 'toggleClass').and.callFake((classNames, show) => { + jest.spyOn(context, 'toggleClass').mockImplementation((classNames, show) => { expect(classNames).toEqual('disable-animation js-popover-show'); expect(show).toEqual(true); done(); @@ -80,7 +80,7 @@ describe('popover', () => { toggleClass: () => {}, }; - spyOn(context, 'popover').and.callFake(method => { + jest.spyOn(context, 'popover').mockImplementation(method => { expect(method).toEqual('hide'); done(); }); @@ -95,7 +95,7 @@ describe('popover', () => { toggleClass: () => {}, }; - spyOn(context, 'toggleClass').and.callFake((classNames, show) => { + jest.spyOn(context, 'toggleClass').mockImplementation((classNames, show) => { expect(classNames).toEqual('disable-animation js-popover-show'); expect(show).toEqual(false); done(); @@ -112,13 +112,13 @@ describe('popover', () => { length: 0, }; - spyOn($.fn, 'init').and.callFake(selector => - selector === '.popover:hover' ? fakeJquery : $.fn, - ); - spyOn(togglePopover, 'call'); + jest + .spyOn($.fn, 'init') + .mockImplementation(selector => (selector === '.popover:hover' ? fakeJquery : $.fn)); + jest.spyOn(togglePopover, 'call').mockImplementation(() => {}); mouseleave(); - expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), false); + expect(togglePopover.call).toHaveBeenCalledWith(expect.any(Object), false); }); it('does not call hide popover if .popover:hover is true', () => { @@ -126,10 +126,10 @@ describe('popover', () => { length: 1, }; - spyOn($.fn, 'init').and.callFake(selector => - selector === '.popover:hover' ? fakeJquery : $.fn, - ); - spyOn(togglePopover, 'call'); + jest + .spyOn($.fn, 'init') + .mockImplementation(selector => (selector === '.popover:hover' ? fakeJquery : $.fn)); + jest.spyOn(togglePopover, 'call').mockImplementation(() => {}); mouseleave(); expect(togglePopover.call).not.toHaveBeenCalledWith(false); @@ -140,15 +140,15 @@ describe('popover', () => { const context = {}; it('shows popover', () => { - spyOn(togglePopover, 'call').and.returnValue(false); + jest.spyOn(togglePopover, 'call').mockReturnValue(false); mouseenter.call(context); - expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), true); + expect(togglePopover.call).toHaveBeenCalledWith(expect.any(Object), true); }); it('registers mouseleave event if popover is showed', done => { - spyOn(togglePopover, 'call').and.returnValue(true); - spyOn($.fn, 'on').and.callFake(eventName => { + jest.spyOn(togglePopover, 'call').mockReturnValue(true); + jest.spyOn($.fn, 'on').mockImplementation(eventName => { expect(eventName).toEqual('mouseleave'); done(); }); @@ -156,8 +156,8 @@ describe('popover', () => { }); it('does not register mouseleave event if popover is not showed', () => { - spyOn(togglePopover, 'call').and.returnValue(false); - const spy = spyOn($.fn, 'on').and.callFake(() => {}); + jest.spyOn(togglePopover, 'call').mockReturnValue(false); + const spy = jest.spyOn($.fn, 'on').mockImplementation(() => {}); mouseenter.call(context); expect(spy).not.toHaveBeenCalled(); diff --git a/spec/frontend/sidebar/sidebar_store_spec.js b/spec/frontend/sidebar/sidebar_store_spec.js new file mode 100644 index 00000000000..6d063a7cfcf --- /dev/null +++ b/spec/frontend/sidebar/sidebar_store_spec.js @@ -0,0 +1,168 @@ +import SidebarStore from '~/sidebar/stores/sidebar_store'; +import Mock from './mock_data'; +import UsersMockHelper from '../helpers/user_mock_data_helper'; + +const ASSIGNEE = { + id: 2, + name: 'gitlab user 2', + username: 'gitlab2', + avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', +}; + +const ANOTHER_ASSINEE = { + id: 3, + name: 'gitlab user 3', + username: 'gitlab3', + avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', +}; + +const PARTICIPANT = { + id: 1, + state: 'active', + username: 'marcene', + name: 'Allie Will', + web_url: 'foo.com', + avatar_url: 'gravatar.com/avatar/xxx', +}; + +const PARTICIPANT_LIST = [PARTICIPANT, { ...PARTICIPANT, id: 2 }, { ...PARTICIPANT, id: 3 }]; + +describe('Sidebar store', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + + beforeEach(() => { + testContext.store = new SidebarStore({ + currentUser: { + id: 1, + name: 'Administrator', + username: 'root', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + }, + editable: true, + rootPath: '/', + endpoint: '/gitlab-org/gitlab-shell/issues/5.json', + }); + }); + + afterEach(() => { + SidebarStore.singleton = null; + }); + + it('has default isFetching values', () => { + expect(testContext.store.isFetching.assignees).toBe(true); + }); + + it('adds a new assignee', () => { + testContext.store.addAssignee(ASSIGNEE); + + expect(testContext.store.assignees.length).toEqual(1); + }); + + it('removes an assignee', () => { + testContext.store.removeAssignee(ASSIGNEE); + + expect(testContext.store.assignees.length).toEqual(0); + }); + + it('finds an existent assignee', () => { + let foundAssignee; + + testContext.store.addAssignee(ASSIGNEE); + foundAssignee = testContext.store.findAssignee(ASSIGNEE); + + expect(foundAssignee).toBeDefined(); + expect(foundAssignee).toEqual(ASSIGNEE); + foundAssignee = testContext.store.findAssignee(ANOTHER_ASSINEE); + + expect(foundAssignee).toBeUndefined(); + }); + + it('removes all assignees', () => { + testContext.store.removeAllAssignees(); + + expect(testContext.store.assignees.length).toEqual(0); + }); + + it('sets participants data', () => { + expect(testContext.store.participants.length).toEqual(0); + + testContext.store.setParticipantsData({ + participants: PARTICIPANT_LIST, + }); + + expect(testContext.store.isFetching.participants).toEqual(false); + expect(testContext.store.participants.length).toEqual(PARTICIPANT_LIST.length); + }); + + it('sets subcriptions data', () => { + expect(testContext.store.subscribed).toEqual(null); + + testContext.store.setSubscriptionsData({ + subscribed: true, + }); + + expect(testContext.store.isFetching.subscriptions).toEqual(false); + expect(testContext.store.subscribed).toEqual(true); + }); + + it('set assigned data', () => { + const users = { + assignees: UsersMockHelper.createNumberRandomUsers(3), + }; + + testContext.store.setAssigneeData(users); + + expect(testContext.store.isFetching.assignees).toBe(false); + expect(testContext.store.assignees.length).toEqual(3); + }); + + it('sets fetching state', () => { + expect(testContext.store.isFetching.participants).toEqual(true); + + testContext.store.setFetchingState('participants', false); + + expect(testContext.store.isFetching.participants).toEqual(false); + }); + + it('sets loading state', () => { + testContext.store.setLoadingState('assignees', true); + + expect(testContext.store.isLoading.assignees).toEqual(true); + }); + + it('set time tracking data', () => { + testContext.store.setTimeTrackingData(Mock.time); + + expect(testContext.store.timeEstimate).toEqual(Mock.time.time_estimate); + expect(testContext.store.totalTimeSpent).toEqual(Mock.time.total_time_spent); + expect(testContext.store.humanTimeEstimate).toEqual(Mock.time.human_time_estimate); + expect(testContext.store.humanTotalTimeSpent).toEqual(Mock.time.human_total_time_spent); + }); + + it('set autocomplete projects', () => { + const projects = [{ id: 0 }]; + testContext.store.setAutocompleteProjects(projects); + + expect(testContext.store.autocompleteProjects).toEqual(projects); + }); + + it('sets subscribed state', () => { + expect(testContext.store.subscribed).toEqual(null); + + testContext.store.setSubscribedState(true); + + expect(testContext.store.subscribed).toEqual(true); + }); + + it('set move to project ID', () => { + const projectId = 7; + testContext.store.setMoveToProjectId(projectId); + + expect(testContext.store.moveToProjectId).toEqual(projectId); + }); +}); diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/frontend/syntax_highlight_spec.js index 99c47fa31d4..d2fb5983f7b 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/frontend/syntax_highlight_spec.js @@ -3,19 +3,19 @@ import $ from 'jquery'; import syntaxHighlight from '~/syntax_highlight'; -describe('Syntax Highlighter', function() { - const stubUserColorScheme = function(value) { +describe('Syntax Highlighter', () => { + const stubUserColorScheme = value => { if (window.gon == null) { window.gon = {}; } return (window.gon.user_color_scheme = value); }; - describe('on a js-syntax-highlight element', function() { - beforeEach(function() { - return setFixtures('<div class="js-syntax-highlight"></div>'); + describe('on a js-syntax-highlight element', () => { + beforeEach(() => { + setFixtures('<div class="js-syntax-highlight"></div>'); }); - it('applies syntax highlighting', function() { + it('applies syntax highlighting', () => { stubUserColorScheme('monokai'); syntaxHighlight($('.js-syntax-highlight')); @@ -23,14 +23,14 @@ describe('Syntax Highlighter', function() { }); }); - describe('on a parent element', function() { - beforeEach(function() { - return setFixtures( + describe('on a parent element', () => { + beforeEach(() => { + setFixtures( '<div class="parent">\n <div class="js-syntax-highlight"></div>\n <div class="foo"></div>\n <div class="js-syntax-highlight"></div>\n</div>', ); }); - it('applies highlighting to all applicable children', function() { + it('applies highlighting to all applicable children', () => { stubUserColorScheme('monokai'); syntaxHighlight($('.parent')); @@ -38,11 +38,9 @@ describe('Syntax Highlighter', function() { expect($('.monokai').length).toBe(2); }); - it('prevents an infinite loop when no matches exist', function() { + it('prevents an infinite loop when no matches exist', () => { setFixtures('<div></div>'); - const highlight = function() { - return syntaxHighlight($('div')); - }; + const highlight = () => syntaxHighlight($('div')); expect(highlight).not.toThrow(); }); diff --git a/spec/javascripts/task_list_spec.js b/spec/frontend/task_list_spec.js index 563f402de58..1261833e3ec 100644 --- a/spec/javascripts/task_list_spec.js +++ b/spec/frontend/task_list_spec.js @@ -25,10 +25,10 @@ describe('TaskList', () => { }); it('should call init when the class constructed', () => { - spyOn(TaskList.prototype, 'init').and.callThrough(); - spyOn(TaskList.prototype, 'disable'); - spyOn($.prototype, 'taskList'); - spyOn($.prototype, 'on'); + jest.spyOn(TaskList.prototype, 'init'); + jest.spyOn(TaskList.prototype, 'disable').mockImplementation(() => {}); + jest.spyOn($.prototype, 'taskList').mockImplementation(() => {}); + jest.spyOn($.prototype, 'on').mockImplementation(() => {}); taskList = createTaskList(); const $taskListEl = $(taskList.taskListContainerSelector); @@ -59,7 +59,7 @@ describe('TaskList', () => { describe('disableTaskListItems', () => { it('should call taskList method with disable param', () => { - spyOn($.prototype, 'taskList'); + jest.spyOn($.prototype, 'taskList').mockImplementation(() => {}); taskList.disableTaskListItems({ currentTarget }); @@ -69,7 +69,7 @@ describe('TaskList', () => { describe('enableTaskListItems', () => { it('should call taskList method with enable param', () => { - spyOn($.prototype, 'taskList'); + jest.spyOn($.prototype, 'taskList').mockImplementation(() => {}); taskList.enableTaskListItems({ currentTarget }); @@ -79,8 +79,8 @@ describe('TaskList', () => { describe('disable', () => { it('should disable task list items and off document event', () => { - spyOn(taskList, 'disableTaskListItems'); - spyOn($.prototype, 'off'); + jest.spyOn(taskList, 'disableTaskListItems').mockImplementation(() => {}); + jest.spyOn($.prototype, 'off').mockImplementation(() => {}); taskList.disable(); @@ -95,10 +95,10 @@ describe('TaskList', () => { describe('update', () => { it('should disable task list items and make a patch request then enable them again', done => { const response = { data: { lock_version: 3 } }; - spyOn(taskList, 'enableTaskListItems'); - spyOn(taskList, 'disableTaskListItems'); - spyOn(taskList, 'onSuccess'); - spyOn(axios, 'patch').and.returnValue(Promise.resolve(response)); + jest.spyOn(taskList, 'enableTaskListItems').mockImplementation(() => {}); + jest.spyOn(taskList, 'disableTaskListItems').mockImplementation(() => {}); + jest.spyOn(taskList, 'onSuccess').mockImplementation(() => {}); + jest.spyOn(axios, 'patch').mockReturnValue(Promise.resolve(response)); const value = 'hello world'; const endpoint = '/foo'; @@ -139,9 +139,9 @@ describe('TaskList', () => { it('should handle request error and enable task list items', done => { const response = { data: { error: 1 } }; - spyOn(taskList, 'enableTaskListItems'); - spyOn(taskList, 'onError'); - spyOn(axios, 'patch').and.returnValue(Promise.reject({ response })); // eslint-disable-line prefer-promise-reject-errors + jest.spyOn(taskList, 'enableTaskListItems').mockImplementation(() => {}); + jest.spyOn(taskList, 'onError').mockImplementation(() => {}); + jest.spyOn(axios, 'patch').mockReturnValue(Promise.reject({ response })); // eslint-disable-line prefer-promise-reject-errors const event = { detail: {} }; taskList diff --git a/spec/frontend/version_check_image_spec.js b/spec/frontend/version_check_image_spec.js new file mode 100644 index 00000000000..2ab157105a1 --- /dev/null +++ b/spec/frontend/version_check_image_spec.js @@ -0,0 +1,42 @@ +import $ from 'jquery'; +import VersionCheckImage from '~/version_check_image'; +import ClassSpecHelper from './helpers/class_spec_helper'; + +describe('VersionCheckImage', () => { + let testContext; + + beforeEach(() => { + testContext = {}; + }); + + describe('bindErrorEvent', () => { + ClassSpecHelper.itShouldBeAStaticMethod(VersionCheckImage, 'bindErrorEvent'); + + beforeEach(() => { + testContext.imageElement = $('<div></div>'); + }); + + it('registers an error event', () => { + jest.spyOn($.prototype, 'on').mockImplementation(() => {}); + // eslint-disable-next-line func-names + jest.spyOn($.prototype, 'off').mockImplementation(function() { + return this; + }); + + VersionCheckImage.bindErrorEvent(testContext.imageElement); + + expect($.prototype.off).toHaveBeenCalledWith('error'); + expect($.prototype.on).toHaveBeenCalledWith('error', expect.any(Function)); + }); + + it('hides the imageElement on error', () => { + jest.spyOn($.prototype, 'hide').mockImplementation(() => {}); + + VersionCheckImage.bindErrorEvent(testContext.imageElement); + + testContext.imageElement.trigger('error'); + + expect($.prototype.hide).toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/gl_modal_vuex_spec.js b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js index eb78d37db3e..4b7636041b6 100644 --- a/spec/javascripts/vue_shared/components/gl_modal_vuex_spec.js +++ b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js @@ -45,8 +45,8 @@ describe('GlModalVuex', () => { state = createState(); actions = { - show: jasmine.createSpy('show'), - hide: jasmine.createSpy('hide'), + show: jest.fn(), + hide: jest.fn(), }; }); @@ -81,7 +81,7 @@ describe('GlModalVuex', () => { }); it('passes listeners through to gl-modal', () => { - const ok = jasmine.createSpy('ok'); + const ok = jest.fn(); factory({ listeners: { ok }, @@ -119,7 +119,7 @@ describe('GlModalVuex', () => { state.isVisible = false; factory(); - const rootEmit = spyOn(wrapper.vm.$root, '$emit'); + const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit'); state.isVisible = true; @@ -136,7 +136,7 @@ describe('GlModalVuex', () => { state.isVisible = true; factory(); - const rootEmit = spyOn(wrapper.vm.$root, '$emit'); + const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit'); state.isVisible = false; diff --git a/spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js index dc929e83eb7..3c5e7500ba7 100644 --- a/spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js +++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js @@ -92,7 +92,7 @@ describe('Suggestion Diff component', () => { describe('applySuggestion', () => { it('emits apply event when applySuggestion is called', () => { const callback = () => {}; - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.applySuggestion(callback); expect(vm.$emit).toHaveBeenCalledWith('apply', { suggestionId: vm.suggestion.id, callback }); diff --git a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js index 96bc3b0cc17..9f0cdc651b6 100644 --- a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_list_spec.js +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js @@ -86,7 +86,7 @@ describe('UserAvatarList', () => { expect(linkProps).toEqual( items.map(x => - jasmine.objectContaining({ + expect.objectContaining({ linkHref: x.web_url, imgSrc: x.avatar_url, imgAlt: x.name, diff --git a/spec/javascripts/behaviors/bind_in_out_spec.js b/spec/javascripts/behaviors/bind_in_out_spec.js deleted file mode 100644 index 0c214f5886a..00000000000 --- a/spec/javascripts/behaviors/bind_in_out_spec.js +++ /dev/null @@ -1,192 +0,0 @@ -import BindInOut from '~/behaviors/bind_in_out'; -import ClassSpecHelper from '../helpers/class_spec_helper'; - -describe('BindInOut', function() { - describe('constructor', function() { - beforeEach(function() { - this.in = {}; - this.out = {}; - - this.bindInOut = new BindInOut(this.in, this.out); - }); - - it('should set .in', function() { - expect(this.bindInOut.in).toBe(this.in); - }); - - it('should set .out', function() { - expect(this.bindInOut.out).toBe(this.out); - }); - - it('should set .eventWrapper', function() { - expect(this.bindInOut.eventWrapper).toEqual({}); - }); - - describe('if .in is an input', function() { - beforeEach(function() { - this.bindInOut = new BindInOut({ tagName: 'INPUT' }); - }); - - it('should set .eventType to keyup ', function() { - expect(this.bindInOut.eventType).toEqual('keyup'); - }); - }); - - describe('if .in is a textarea', function() { - beforeEach(function() { - this.bindInOut = new BindInOut({ tagName: 'TEXTAREA' }); - }); - - it('should set .eventType to keyup ', function() { - expect(this.bindInOut.eventType).toEqual('keyup'); - }); - }); - - describe('if .in is not an input or textarea', function() { - beforeEach(function() { - this.bindInOut = new BindInOut({ tagName: 'SELECT' }); - }); - - it('should set .eventType to change ', function() { - expect(this.bindInOut.eventType).toEqual('change'); - }); - }); - }); - - describe('addEvents', function() { - beforeEach(function() { - this.in = jasmine.createSpyObj('in', ['addEventListener']); - - this.bindInOut = new BindInOut(this.in); - - this.addEvents = this.bindInOut.addEvents(); - }); - - it('should set .eventWrapper.updateOut', function() { - expect(this.bindInOut.eventWrapper.updateOut).toEqual(jasmine.any(Function)); - }); - - it('should call .addEventListener', function() { - expect(this.in.addEventListener).toHaveBeenCalledWith( - this.bindInOut.eventType, - this.bindInOut.eventWrapper.updateOut, - ); - }); - - it('should return the instance', function() { - expect(this.addEvents).toBe(this.bindInOut); - }); - }); - - describe('updateOut', function() { - beforeEach(function() { - this.in = { value: 'the-value' }; - this.out = { textContent: 'not-the-value' }; - - this.bindInOut = new BindInOut(this.in, this.out); - - this.updateOut = this.bindInOut.updateOut(); - }); - - it('should set .out.textContent to .in.value', function() { - expect(this.out.textContent).toBe(this.in.value); - }); - - it('should return the instance', function() { - expect(this.updateOut).toBe(this.bindInOut); - }); - }); - - describe('removeEvents', function() { - beforeEach(function() { - this.in = jasmine.createSpyObj('in', ['removeEventListener']); - this.updateOut = () => {}; - - this.bindInOut = new BindInOut(this.in); - this.bindInOut.eventWrapper.updateOut = this.updateOut; - - this.removeEvents = this.bindInOut.removeEvents(); - }); - - it('should call .removeEventListener', function() { - expect(this.in.removeEventListener).toHaveBeenCalledWith( - this.bindInOut.eventType, - this.updateOut, - ); - }); - - it('should return the instance', function() { - expect(this.removeEvents).toBe(this.bindInOut); - }); - }); - - describe('initAll', function() { - beforeEach(function() { - this.ins = [0, 1, 2]; - this.instances = []; - - spyOn(document, 'querySelectorAll').and.returnValue(this.ins); - spyOn(Array.prototype, 'map').and.callThrough(); - spyOn(BindInOut, 'init'); - - this.initAll = BindInOut.initAll(); - }); - - ClassSpecHelper.itShouldBeAStaticMethod(BindInOut, 'initAll'); - - it('should call .querySelectorAll', function() { - expect(document.querySelectorAll).toHaveBeenCalledWith('*[data-bind-in]'); - }); - - it('should call .map', function() { - expect(Array.prototype.map).toHaveBeenCalledWith(jasmine.any(Function)); - }); - - it('should call .init for each element', function() { - expect(BindInOut.init.calls.count()).toEqual(3); - }); - - it('should return an array of instances', function() { - expect(this.initAll).toEqual(jasmine.any(Array)); - }); - }); - - describe('init', function() { - beforeEach(function() { - spyOn(BindInOut.prototype, 'addEvents').and.callFake(function() { - return this; - }); - spyOn(BindInOut.prototype, 'updateOut').and.callFake(function() { - return this; - }); - - this.init = BindInOut.init({}, {}); - }); - - ClassSpecHelper.itShouldBeAStaticMethod(BindInOut, 'init'); - - it('should call .addEvents', function() { - expect(BindInOut.prototype.addEvents).toHaveBeenCalled(); - }); - - it('should call .updateOut', function() { - expect(BindInOut.prototype.updateOut).toHaveBeenCalled(); - }); - - describe('if no anOut is provided', function() { - beforeEach(function() { - this.anIn = { dataset: { bindIn: 'the-data-bind-in' } }; - - spyOn(document, 'querySelector'); - - BindInOut.init(this.anIn); - }); - - it('should call .querySelector', function() { - expect(document.querySelector).toHaveBeenCalledWith( - `*[data-bind-out="${this.anIn.dataset.bindIn}"]`, - ); - }); - }); - }); -}); diff --git a/spec/javascripts/droplab/constants_spec.js b/spec/javascripts/droplab/constants_spec.js deleted file mode 100644 index 23b69defec6..00000000000 --- a/spec/javascripts/droplab/constants_spec.js +++ /dev/null @@ -1,39 +0,0 @@ -import * as constants from '~/droplab/constants'; - -describe('constants', function() { - describe('DATA_TRIGGER', function() { - it('should be `data-dropdown-trigger`', function() { - expect(constants.DATA_TRIGGER).toBe('data-dropdown-trigger'); - }); - }); - - describe('DATA_DROPDOWN', function() { - it('should be `data-dropdown`', function() { - expect(constants.DATA_DROPDOWN).toBe('data-dropdown'); - }); - }); - - describe('SELECTED_CLASS', function() { - it('should be `droplab-item-selected`', function() { - expect(constants.SELECTED_CLASS).toBe('droplab-item-selected'); - }); - }); - - describe('ACTIVE_CLASS', function() { - it('should be `droplab-item-active`', function() { - expect(constants.ACTIVE_CLASS).toBe('droplab-item-active'); - }); - }); - - describe('TEMPLATE_REGEX', function() { - it('should be a handlebars templating syntax regex', function() { - expect(constants.TEMPLATE_REGEX).toEqual(/\{\{(.+?)\}\}/g); - }); - }); - - describe('IGNORE_CLASS', function() { - it('should be `droplab-item-ignore`', function() { - expect(constants.IGNORE_CLASS).toBe('droplab-item-ignore'); - }); - }); -}); diff --git a/spec/javascripts/polyfills/element_spec.js b/spec/javascripts/polyfills/element_spec.js deleted file mode 100644 index d35df595c72..00000000000 --- a/spec/javascripts/polyfills/element_spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import '~/commons/polyfills/element'; - -describe('Element polyfills', function() { - beforeEach(() => { - this.element = document.createElement('ul'); - }); - - describe('matches', () => { - it('returns true if element matches the selector', () => { - expect(this.element.matches('ul')).toBeTruthy(); - }); - - it("returns false if element doesn't match the selector", () => { - expect(this.element.matches('.not-an-element')).toBeFalsy(); - }); - }); - - describe('closest', () => { - beforeEach(() => { - this.childElement = document.createElement('li'); - this.element.appendChild(this.childElement); - }); - - it('returns the closest parent that matches the selector', () => { - expect(this.childElement.closest('ul').toString()).toBe(this.element.toString()); - }); - - it('returns itself if it matches the selector', () => { - expect(this.childElement.closest('li').toString()).toBe(this.childElement.toString()); - }); - - it('returns undefined if nothing matches the selector', () => { - expect(this.childElement.closest('.no-an-element')).toBeFalsy(); - }); - }); -}); diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js deleted file mode 100644 index dc85292c23e..00000000000 --- a/spec/javascripts/project_select_combo_button_spec.js +++ /dev/null @@ -1,124 +0,0 @@ -import $ from 'jquery'; -import ProjectSelectComboButton from '~/project_select_combo_button'; - -const fixturePath = 'static/project_select_combo_button.html'; - -describe('Project Select Combo Button', function() { - preloadFixtures(fixturePath); - - beforeEach(function() { - this.defaults = { - label: 'Select project to create issue', - groupId: 12345, - projectMeta: { - name: 'My Cool Project', - url: 'http://mycoolproject.com', - }, - newProjectMeta: { - name: 'My Other Cool Project', - url: 'http://myothercoolproject.com', - }, - localStorageKey: 'group-12345-new-issue-recent-project', - relativePath: 'issues/new', - }; - - loadFixtures(fixturePath); - - this.newItemBtn = document.querySelector('.new-project-item-link'); - this.projectSelectInput = document.querySelector('.project-item-select'); - }); - - describe('on page load when localStorage is empty', function() { - beforeEach(function() { - this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); - }); - - it('newItemBtn href is null', function() { - expect(this.newItemBtn.getAttribute('href')).toBe(''); - }); - - it('newItemBtn text is the plain default label', function() { - expect(this.newItemBtn.textContent).toBe(this.defaults.label); - }); - }); - - describe('on page load when localStorage is filled', function() { - beforeEach(function() { - window.localStorage.setItem( - this.defaults.localStorageKey, - JSON.stringify(this.defaults.projectMeta), - ); - this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); - }); - - it('newItemBtn href is correctly set', function() { - expect(this.newItemBtn.getAttribute('href')).toBe(this.defaults.projectMeta.url); - }); - - it('newItemBtn text is the cached label', function() { - expect(this.newItemBtn.textContent).toBe(`New issue in ${this.defaults.projectMeta.name}`); - }); - - afterEach(function() { - window.localStorage.clear(); - }); - }); - - describe('after selecting a new project', function() { - beforeEach(function() { - this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); - - // mock the effect of selecting an item from the projects dropdown (select2) - $('.project-item-select') - .val(JSON.stringify(this.defaults.newProjectMeta)) - .trigger('change'); - }); - - it('newItemBtn href is correctly set', function() { - expect(this.newItemBtn.getAttribute('href')).toBe('http://myothercoolproject.com/issues/new'); - }); - - it('newItemBtn text is the selected project label', function() { - expect(this.newItemBtn.textContent).toBe(`New issue in ${this.defaults.newProjectMeta.name}`); - }); - - afterEach(function() { - window.localStorage.clear(); - }); - }); - - describe('deriveTextVariants', function() { - beforeEach(function() { - this.mockExecutionContext = { - resourceType: '', - resourceLabel: '', - }; - - this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); - - this.method = this.comboButton.deriveTextVariants.bind(this.mockExecutionContext); - }); - - it('correctly derives test variants for merge requests', function() { - this.mockExecutionContext.resourceType = 'merge_requests'; - this.mockExecutionContext.resourceLabel = 'New merge request'; - - const returnedVariants = this.method(); - - expect(returnedVariants.localStorageItemType).toBe('new-merge-request'); - expect(returnedVariants.defaultTextPrefix).toBe('New merge request'); - expect(returnedVariants.presetTextSuffix).toBe('merge request'); - }); - - it('correctly derives text variants for issues', function() { - this.mockExecutionContext.resourceType = 'issues'; - this.mockExecutionContext.resourceLabel = 'New issue'; - - const returnedVariants = this.method(); - - expect(returnedVariants.localStorageItemType).toBe('new-issue'); - expect(returnedVariants.defaultTextPrefix).toBe('New issue'); - expect(returnedVariants.presetTextSuffix).toBe('issue'); - }); - }); -}); diff --git a/spec/javascripts/sidebar/sidebar_store_spec.js b/spec/javascripts/sidebar/sidebar_store_spec.js deleted file mode 100644 index 85ff70fffbd..00000000000 --- a/spec/javascripts/sidebar/sidebar_store_spec.js +++ /dev/null @@ -1,162 +0,0 @@ -import SidebarStore from '~/sidebar/stores/sidebar_store'; -import Mock from './mock_data'; -import UsersMockHelper from '../helpers/user_mock_data_helper'; - -const ASSIGNEE = { - id: 2, - name: 'gitlab user 2', - username: 'gitlab2', - avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', -}; - -const ANOTHER_ASSINEE = { - id: 3, - name: 'gitlab user 3', - username: 'gitlab3', - avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', -}; - -const PARTICIPANT = { - id: 1, - state: 'active', - username: 'marcene', - name: 'Allie Will', - web_url: 'foo.com', - avatar_url: 'gravatar.com/avatar/xxx', -}; - -const PARTICIPANT_LIST = [PARTICIPANT, { ...PARTICIPANT, id: 2 }, { ...PARTICIPANT, id: 3 }]; - -describe('Sidebar store', function() { - beforeEach(() => { - this.store = new SidebarStore({ - currentUser: { - id: 1, - name: 'Administrator', - username: 'root', - avatar_url: - 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', - }, - editable: true, - rootPath: '/', - endpoint: '/gitlab-org/gitlab-shell/issues/5.json', - }); - }); - - afterEach(() => { - SidebarStore.singleton = null; - }); - - it('has default isFetching values', () => { - expect(this.store.isFetching.assignees).toBe(true); - }); - - it('adds a new assignee', () => { - this.store.addAssignee(ASSIGNEE); - - expect(this.store.assignees.length).toEqual(1); - }); - - it('removes an assignee', () => { - this.store.removeAssignee(ASSIGNEE); - - expect(this.store.assignees.length).toEqual(0); - }); - - it('finds an existent assignee', () => { - let foundAssignee; - - this.store.addAssignee(ASSIGNEE); - foundAssignee = this.store.findAssignee(ASSIGNEE); - - expect(foundAssignee).toBeDefined(); - expect(foundAssignee).toEqual(ASSIGNEE); - foundAssignee = this.store.findAssignee(ANOTHER_ASSINEE); - - expect(foundAssignee).toBeUndefined(); - }); - - it('removes all assignees', () => { - this.store.removeAllAssignees(); - - expect(this.store.assignees.length).toEqual(0); - }); - - it('sets participants data', () => { - expect(this.store.participants.length).toEqual(0); - - this.store.setParticipantsData({ - participants: PARTICIPANT_LIST, - }); - - expect(this.store.isFetching.participants).toEqual(false); - expect(this.store.participants.length).toEqual(PARTICIPANT_LIST.length); - }); - - it('sets subcriptions data', () => { - expect(this.store.subscribed).toEqual(null); - - this.store.setSubscriptionsData({ - subscribed: true, - }); - - expect(this.store.isFetching.subscriptions).toEqual(false); - expect(this.store.subscribed).toEqual(true); - }); - - it('set assigned data', () => { - const users = { - assignees: UsersMockHelper.createNumberRandomUsers(3), - }; - - this.store.setAssigneeData(users); - - expect(this.store.isFetching.assignees).toBe(false); - expect(this.store.assignees.length).toEqual(3); - }); - - it('sets fetching state', () => { - expect(this.store.isFetching.participants).toEqual(true); - - this.store.setFetchingState('participants', false); - - expect(this.store.isFetching.participants).toEqual(false); - }); - - it('sets loading state', () => { - this.store.setLoadingState('assignees', true); - - expect(this.store.isLoading.assignees).toEqual(true); - }); - - it('set time tracking data', () => { - this.store.setTimeTrackingData(Mock.time); - - expect(this.store.timeEstimate).toEqual(Mock.time.time_estimate); - expect(this.store.totalTimeSpent).toEqual(Mock.time.total_time_spent); - expect(this.store.humanTimeEstimate).toEqual(Mock.time.human_time_estimate); - expect(this.store.humanTotalTimeSpent).toEqual(Mock.time.human_total_time_spent); - }); - - it('set autocomplete projects', () => { - const projects = [{ id: 0 }]; - this.store.setAutocompleteProjects(projects); - - expect(this.store.autocompleteProjects).toEqual(projects); - }); - - it('sets subscribed state', () => { - expect(this.store.subscribed).toEqual(null); - - this.store.setSubscribedState(true); - - expect(this.store.subscribed).toEqual(true); - }); - - it('set move to project ID', () => { - const projectId = 7; - this.store.setMoveToProjectId(projectId); - - expect(this.store.moveToProjectId).toEqual(projectId); - }); -}); diff --git a/spec/javascripts/version_check_image_spec.js b/spec/javascripts/version_check_image_spec.js deleted file mode 100644 index 0e69fcc4c5f..00000000000 --- a/spec/javascripts/version_check_image_spec.js +++ /dev/null @@ -1,35 +0,0 @@ -import $ from 'jquery'; -import VersionCheckImage from '~/version_check_image'; -import ClassSpecHelper from './helpers/class_spec_helper'; - -describe('VersionCheckImage', function() { - describe('bindErrorEvent', function() { - ClassSpecHelper.itShouldBeAStaticMethod(VersionCheckImage, 'bindErrorEvent'); - - beforeEach(function() { - this.imageElement = $('<div></div>'); - }); - - it('registers an error event', function() { - spyOn($.prototype, 'on'); - spyOn($.prototype, 'off').and.callFake(function() { - return this; - }); - - VersionCheckImage.bindErrorEvent(this.imageElement); - - expect($.prototype.off).toHaveBeenCalledWith('error'); - expect($.prototype.on).toHaveBeenCalledWith('error', jasmine.any(Function)); - }); - - it('hides the imageElement on error', function() { - spyOn($.prototype, 'hide'); - - VersionCheckImage.bindErrorEvent(this.imageElement); - - this.imageElement.trigger('error'); - - expect($.prototype.hide).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/lib/sentry/client/issue_spec.rb b/spec/lib/sentry/client/issue_spec.rb index 17548e2081d..20665c59a8d 100644 --- a/spec/lib/sentry/client/issue_spec.rb +++ b/spec/lib/sentry/client/issue_spec.rb @@ -74,6 +74,10 @@ describe Sentry::Client::Issue do it 'has a correct GitLab issue url' do expect(subject.gitlab_issue).to eq('https://gitlab.com/gitlab-org/gitlab/issues/1') end + + it 'has the correct tags' do + expect(subject.tags).to eq({ level: issue_sample_response['level'], logger: issue_sample_response['logger'] }) + end end end end diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index c3db516f253..1346a43335e 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -17,7 +17,8 @@ describe ChatMessage::WikiPageMessage do object_attributes: { title: 'Wiki page title', url: 'http://url.com', - content: 'Wiki page description' + content: 'Wiki page content', + message: 'Wiki page commit message' } } end @@ -57,10 +58,10 @@ describe ChatMessage::WikiPageMessage do args[:object_attributes][:action] = 'create' end - it 'returns the attachment for a new wiki page' do + it 'returns the commit message for a new wiki page' do expect(subject.attachments).to eq([ { - text: "Wiki page description", + text: "Wiki page commit message", color: color } ]) @@ -72,10 +73,10 @@ describe ChatMessage::WikiPageMessage do args[:object_attributes][:action] = 'update' end - it 'returns the attachment for an updated wiki page' do + it 'returns the commit message for an updated wiki page' do expect(subject.attachments).to eq([ { - text: "Wiki page description", + text: "Wiki page commit message", color: color } ]) @@ -119,8 +120,8 @@ describe ChatMessage::WikiPageMessage do args[:object_attributes][:action] = 'create' end - it 'returns the attachment for a new wiki page' do - expect(subject.attachments).to eq('Wiki page description') + it 'returns the commit message for a new wiki page' do + expect(subject.attachments).to eq('Wiki page commit message') end end @@ -129,8 +130,8 @@ describe ChatMessage::WikiPageMessage do args[:object_attributes][:action] = 'update' end - it 'returns the attachment for an updated wiki page' do - expect(subject.attachments).to eq('Wiki page description') + it 'returns the commit message for an updated wiki page' do + expect(subject.attachments).to eq('Wiki page commit message') end end end |