diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-05 15:09:31 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-05 15:09:31 +0300 |
commit | f44809bf96e636a28394c9849dbea5f68e8c910c (patch) | |
tree | dec9c52174c79605a86926693a7dc5e976af4fcf /spec | |
parent | 7d175806de998d736b2f0b3d2bda8f4737d9820c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
26 files changed, 238 insertions, 151 deletions
diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb index 994cea4c84f..e6b8da690a2 100644 --- a/spec/config/application_spec.rb +++ b/spec/config/application_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe Gitlab::Application do # rubocop:disable RSpec/FilePath using RSpec::Parameterized::TableSyntax - FILTERED_PARAM = ActiveSupport::ParameterFilter::FILTERED + filtered_param = ActiveSupport::ParameterFilter::FILTERED context 'when parameters are logged' do describe 'rails does not leak confidential parameters' do @@ -19,11 +19,11 @@ describe Gitlab::Application do # rubocop:disable RSpec/FilePath where(:input_url, :output_query) do '/' | {} '/?safe=1' | { 'safe' => '1' } - '/?private_token=secret' | { 'private_token' => FILTERED_PARAM } - '/?mixed=1&private_token=secret' | { 'mixed' => '1', 'private_token' => FILTERED_PARAM } - '/?note=secret¬eable=1&prefix_note=2' | { 'note' => FILTERED_PARAM, 'noteable' => '1', 'prefix_note' => '2' } - '/?note[note]=secret&target_type=1' | { 'note' => FILTERED_PARAM, 'target_type' => '1' } - '/?safe[note]=secret&target_type=1' | { 'safe' => { 'note' => FILTERED_PARAM }, 'target_type' => '1' } + '/?private_token=secret' | { 'private_token' => filtered_param } + '/?mixed=1&private_token=secret' | { 'mixed' => '1', 'private_token' => filtered_param } + '/?note=secret¬eable=1&prefix_note=2' | { 'note' => filtered_param, 'noteable' => '1', 'prefix_note' => '2' } + '/?note[note]=secret&target_type=1' | { 'note' => filtered_param, 'target_type' => '1' } + '/?safe[note]=secret&target_type=1' | { 'safe' => { 'note' => filtered_param }, 'target_type' => '1' } end with_them do diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb index 5fc65f020d3..41a7456aed5 100644 --- a/spec/features/merge_request/user_resolves_conflicts_spec.rb +++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb @@ -183,14 +183,14 @@ describe 'Merge request > User resolves conflicts', :js do end end - UNRESOLVABLE_CONFLICTS = { + unresolvable_conflicts = { 'conflict-too-large' => 'when the conflicts contain a large file', 'conflict-binary-file' => 'when the conflicts contain a binary file', 'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another', 'conflict-non-utf8' => 'when the conflicts contain a non-UTF-8 file' }.freeze - UNRESOLVABLE_CONFLICTS.each do |source_branch, description| + unresolvable_conflicts.each do |source_branch, description| context description do let(:merge_request) { create_merge_request(source_branch) } diff --git a/spec/features/milestones/user_creates_milestone_spec.rb b/spec/features/milestones/user_creates_milestone_spec.rb index 368a2ddecdf..12cb27b0062 100644 --- a/spec/features/milestones/user_creates_milestone_spec.rb +++ b/spec/features/milestones/user_creates_milestone_spec.rb @@ -14,13 +14,13 @@ describe "User creates milestone", :js do end it "creates milestone" do - TITLE = "v2.3".freeze + title = "v2.3".freeze - fill_in("Title", with: TITLE) + fill_in("Title", with: title) fill_in("Description", with: "# Description header") click_button("Create milestone") - expect(page).to have_content(TITLE) + expect(page).to have_content(title) .and have_content("Issues") .and have_header_with_correct_id_and_link(1, "Description header", "description-header") diff --git a/spec/features/milestones/user_views_milestone_spec.rb b/spec/features/milestones/user_views_milestone_spec.rb index d8bb4902087..ca13e226432 100644 --- a/spec/features/milestones/user_views_milestone_spec.rb +++ b/spec/features/milestones/user_views_milestone_spec.rb @@ -14,13 +14,13 @@ describe "User views milestone" do end it "avoids N+1 database queries" do - ISSUE_PARAMS = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze + issue_params = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze - create(:labeled_issue, ISSUE_PARAMS) + create(:labeled_issue, issue_params) control = ActiveRecord::QueryRecorder.new { visit_milestone } - create(:labeled_issue, ISSUE_PARAMS) + create(:labeled_issue, issue_params) expect { visit_milestone }.not_to exceed_query_limit(control) end diff --git a/spec/features/projects/branches/user_creates_branch_spec.rb b/spec/features/projects/branches/user_creates_branch_spec.rb index 156edb973cd..8aac188160b 100644 --- a/spec/features/projects/branches/user_creates_branch_spec.rb +++ b/spec/features/projects/branches/user_creates_branch_spec.rb @@ -16,18 +16,18 @@ describe "User creates branch", :js do end it "creates new branch" do - BRANCH_NAME = "deploy_keys".freeze + branch_name = "deploy_keys".freeze - create_branch(BRANCH_NAME) + create_branch(branch_name) - expect(page).to have_content(BRANCH_NAME) + expect(page).to have_content(branch_name) end context "when branch name is invalid" do it "does not create new branch" do - INVALID_BRANCH_NAME = "1.0 stable".freeze + invalid_branch_name = "1.0 stable".freeze - fill_in("branch_name", with: INVALID_BRANCH_NAME) + fill_in("branch_name", with: invalid_branch_name) page.find("body").click # defocus the branch_name input select_branch("master") diff --git a/spec/features/projects/commit/comments/user_edits_comments_spec.rb b/spec/features/projects/commit/comments/user_edits_comments_spec.rb index 0fa2b2ff232..29132173674 100644 --- a/spec/features/projects/commit/comments/user_edits_comments_spec.rb +++ b/spec/features/projects/commit/comments/user_edits_comments_spec.rb @@ -19,7 +19,7 @@ describe "User edits a comment on a commit", :js do end it "edits comment" do - NEW_COMMENT_TEXT = "+1 Awesome!".freeze + new_comment_text = "+1 Awesome!".freeze page.within(".main-notes-list") do note = find(".note") @@ -31,14 +31,14 @@ describe "User edits a comment on a commit", :js do page.find(".current-note-edit-form textarea") page.within(".current-note-edit-form") do - fill_in("note[note]", with: NEW_COMMENT_TEXT) + fill_in("note[note]", with: new_comment_text) click_button("Save comment") end wait_for_requests page.within(".note") do - expect(page).to have_content(NEW_COMMENT_TEXT) + expect(page).to have_content(new_comment_text) end end end diff --git a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb index cd9299150b2..45a16fda2cb 100644 --- a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb +++ b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb @@ -88,18 +88,18 @@ describe "User interacts with deploy keys", :js do end it "adds new key" do - DEPLOY_KEY_TITLE = attributes_for(:key)[:title] - DEPLOY_KEY_BODY = attributes_for(:key)[:key] + deploy_key_title = attributes_for(:key)[:title] + deploy_key_body = attributes_for(:key)[:key] - fill_in("deploy_key_title", with: DEPLOY_KEY_TITLE) - fill_in("deploy_key_key", with: DEPLOY_KEY_BODY) + fill_in("deploy_key_title", with: deploy_key_title) + fill_in("deploy_key_key", with: deploy_key_body) click_button("Add key") expect(current_path).to eq(project_settings_repository_path(project)) page.within(".deploy-keys") do - expect(page).to have_content(DEPLOY_KEY_TITLE) + expect(page).to have_content(deploy_key_title) end end end diff --git a/spec/frontend/alert_management/components/alert_management_list_spec.js b/spec/frontend/alert_management/components/alert_management_list_spec.js index e45a9042f71..c0494d736a6 100644 --- a/spec/frontend/alert_management/components/alert_management_list_spec.js +++ b/spec/frontend/alert_management/components/alert_management_list_spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import { GlEmptyState, GlTable, GlAlert, GlLoadingIcon, GlNewDropdown } from '@gitlab/ui'; +import { GlEmptyState, GlTable, GlAlert, GlLoadingIcon, GlNewDropdown, GlIcon } from '@gitlab/ui'; import AlertManagementList from '~/alert_management/components/alert_management_list.vue'; import mockAlerts from '../mocks/alerts.json'; @@ -113,5 +113,22 @@ describe('AlertManagementList', () => { }); expect(findStatusDropdown().exists()).toBe(true); }); + + it('shows correct severity icons', () => { + mountComponent({ + props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, + data: { alerts: mockAlerts, errored: false }, + loading: false, + }); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find(GlTable).exists()).toBe(true); + expect( + findAlertsTable() + .find(GlIcon) + .classes('icon-critical'), + ).toBe(true); + }); + }); }); }); diff --git a/spec/frontend/clusters_list/store/actions_spec.js b/spec/frontend/clusters_list/store/actions_spec.js index e903200bf1d..46132f701be 100644 --- a/spec/frontend/clusters_list/store/actions_spec.js +++ b/spec/frontend/clusters_list/store/actions_spec.js @@ -45,6 +45,3 @@ describe('Clusters store actions', () => { }); }); }); - -// prevent babel-plugin-rewire from generating an invalid default during karma tests -export default () => {}; diff --git a/spec/frontend/contributors/store/actions_spec.js b/spec/frontend/contributors/store/actions_spec.js index fe3e2132d9d..55437da837c 100644 --- a/spec/frontend/contributors/store/actions_spec.js +++ b/spec/frontend/contributors/store/actions_spec.js @@ -55,6 +55,3 @@ describe('Contributors store actions', () => { }); }); }); - -// prevent babel-plugin-rewire from generating an invalid default during karma tests -export default () => {}; diff --git a/spec/frontend/contributors/store/getters_spec.js b/spec/frontend/contributors/store/getters_spec.js index e6342a669b7..a4202e0ef4b 100644 --- a/spec/frontend/contributors/store/getters_spec.js +++ b/spec/frontend/contributors/store/getters_spec.js @@ -74,6 +74,3 @@ describe('Contributors Store Getters', () => { }); }); }); - -// prevent babel-plugin-rewire from generating an invalid default during karma tests -export default () => {}; diff --git a/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js b/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js index 490a2775b67..0ef09b4b87e 100644 --- a/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js +++ b/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js @@ -75,7 +75,7 @@ describe('awsServicesFacade', () => { }); it('return list of regions where each item has a name and value', () => { - expect(fetchRoles()).resolves.toEqual(rolesOutput); + return expect(fetchRoles()).resolves.toEqual(rolesOutput); }); }); @@ -91,7 +91,7 @@ describe('awsServicesFacade', () => { }); it('return list of roles where each item has a name and value', () => { - expect(fetchRegions()).resolves.toEqual(regionsOutput); + return expect(fetchRegions()).resolves.toEqual(regionsOutput); }); }); @@ -112,7 +112,7 @@ describe('awsServicesFacade', () => { }); it('return list of key pairs where each item has a name and value', () => { - expect(fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput); + return expect(fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput); }); }); @@ -133,7 +133,7 @@ describe('awsServicesFacade', () => { }); it('return list of vpcs where each item has a name and value', () => { - expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput); + return expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput); }); }); @@ -151,7 +151,7 @@ describe('awsServicesFacade', () => { }); it('uses name tag value as the vpc name', () => { - expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput); + return expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput); }); }); @@ -167,7 +167,7 @@ describe('awsServicesFacade', () => { }); it('return list of subnets where each item has a name and value', () => { - expect(fetchSubnets({ region, vpc })).resolves.toEqual(subnetsOutput); + return expect(fetchSubnets({ region, vpc })).resolves.toEqual(subnetsOutput); }); }); @@ -189,7 +189,7 @@ describe('awsServicesFacade', () => { }); it('return list of security groups where each item has a name and value', () => { - expect(fetchSecurityGroups({ region, vpc })).resolves.toEqual(securityGroupsOutput); + return expect(fetchSecurityGroups({ region, vpc })).resolves.toEqual(securityGroupsOutput); }); }); }); diff --git a/spec/frontend/mocks_spec.js b/spec/frontend/mocks_spec.js index a4a1fdea396..110c418e579 100644 --- a/spec/frontend/mocks_spec.js +++ b/spec/frontend/mocks_spec.js @@ -8,12 +8,13 @@ describe('Mock auto-injection', () => { failMock = jest.spyOn(global, 'fail').mockImplementation(); }); - it('~/lib/utils/axios_utils', done => { - expect(axios.get('http://gitlab.com')).rejects.toThrow('Unexpected unmocked request'); - setImmediate(() => { - expect(failMock).toHaveBeenCalledTimes(1); - done(); - }); + it('~/lib/utils/axios_utils', () => { + return Promise.all([ + expect(axios.get('http://gitlab.com')).rejects.toThrow('Unexpected unmocked request'), + setImmediate(() => { + expect(failMock).toHaveBeenCalledTimes(1); + }), + ]); }); it('jQuery.ajax()', () => { diff --git a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js index 10fd58f749d..216ec345552 100644 --- a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js +++ b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js @@ -81,7 +81,8 @@ describe('DuplicateDashboardForm', () => { it('with the inital form values', () => { expect(wrapper.emitted().change).toHaveLength(1); - expect(lastChange()).resolves.toEqual({ + + return expect(lastChange()).resolves.toEqual({ branch: '', commitMessage: expect.any(String), dashboard: dashboardGitResponse[0].path, @@ -92,7 +93,7 @@ describe('DuplicateDashboardForm', () => { it('containing an inputted file name', () => { setValue('fileName', 'my_dashboard.yml'); - expect(lastChange()).resolves.toMatchObject({ + return expect(lastChange()).resolves.toMatchObject({ fileName: 'my_dashboard.yml', }); }); @@ -100,7 +101,7 @@ describe('DuplicateDashboardForm', () => { it('containing a default commit message when no message is set', () => { setValue('commitMessage', ''); - expect(lastChange()).resolves.toMatchObject({ + return expect(lastChange()).resolves.toMatchObject({ commitMessage: expect.stringContaining('Create custom dashboard'), }); }); @@ -108,7 +109,7 @@ describe('DuplicateDashboardForm', () => { it('containing an inputted commit message', () => { setValue('commitMessage', 'My commit message'); - expect(lastChange()).resolves.toMatchObject({ + return expect(lastChange()).resolves.toMatchObject({ commitMessage: expect.stringContaining('My commit message'), }); }); @@ -116,7 +117,7 @@ describe('DuplicateDashboardForm', () => { it('containing an inputted branch name', () => { setValue('branchName', 'a-new-branch'); - expect(lastChange()).resolves.toMatchObject({ + return expect(lastChange()).resolves.toMatchObject({ branch: 'a-new-branch', }); }); @@ -125,13 +126,14 @@ describe('DuplicateDashboardForm', () => { setChecked(wrapper.vm.$options.radioVals.DEFAULT); setValue('branchName', 'a-new-branch'); - expect(lastChange()).resolves.toMatchObject({ - branch: defaultBranch, - }); - - return wrapper.vm.$nextTick(() => { - expect(findByRef('branchName').isVisible()).toBe(false); - }); + return Promise.all([ + expect(lastChange()).resolves.toMatchObject({ + branch: defaultBranch, + }), + wrapper.vm.$nextTick(() => { + expect(findByRef('branchName').isVisible()).toBe(false); + }), + ]); }); it('when `new` branch option is chosen, focuses on the branch name input', () => { diff --git a/spec/frontend/notes/old_notes_spec.js b/spec/frontend/notes/old_notes_spec.js index 3f7c94c3a2b..9f3ab4185c4 100644 --- a/spec/frontend/notes/old_notes_spec.js +++ b/spec/frontend/notes/old_notes_spec.js @@ -212,13 +212,6 @@ describe.skip('Old Notes (~/notes.js)', () => { jest.spyOn($note, 'toggleClass'); }); - afterEach(() => { - expect(typeof urlUtility.getLocationHash.mock).toBe('object'); - urlUtility.getLocationHash.mockRestore(); - expect(urlUtility.getLocationHash.mock).toBeUndefined(); - expect(urlUtility.getLocationHash()).toBeNull(); - }); - // urlUtility is a dependency of the notes module. Its getLocatinHash() method should be called internally. it('sets target when hash matches', () => { @@ -629,48 +622,6 @@ describe.skip('Old Notes (~/notes.js)', () => { done(); }); }); - - // This is a bad test carried over from the Karma -> Jest migration. - // The corresponding test in the Karma suite tests for - // elements and methods that don't actually exist, and gives a false - // positive pass. - /* - it('should show flash error message when comment failed to be updated', done => { - mockNotesPost(); - jest.spyOn(notes, 'addFlash').mockName('addFlash'); - - $('.js-comment-button').click(); - - deferredPromise() - .then(() => { - const $noteEl = $notesContainer.find(`#note_${note.id}`); - $noteEl.find('.js-note-edit').click(); - $noteEl.find('textarea.js-note-text').val(updatedComment); - - mockNotesPostError(); - - $noteEl.find('.js-comment-save-button').click(); - notes.updateComment({preventDefault: () => {}}); - }) - .then(() => deferredPromise()) - .then(() => { - const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`); - - expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals - expect( - $updatedNoteEl - .find('.note-text') - .text() - .trim(), - ).toEqual(sampleComment); // See if comment reverted back to original - - expect(notes.addFlash).toHaveBeenCalled(); - expect(notes.flashContainer.style.display).not.toBe('none'); - done(); - }) - .catch(done.fail); - }, 5000); - */ }); describe('postComment with Slash commands', () => { diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js index 4a1790adb09..231d877a25d 100644 --- a/spec/frontend/releases/stores/modules/detail/actions_spec.js +++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js @@ -143,7 +143,7 @@ describe('Release detail actions', () => { { type: types.RECEIVE_UPDATE_RELEASE_SUCCESS }, ])); - describe('when the releaseShowPage feature flag is enabled', () => { + it('redirects to the releases page if releaseShowPage feature flag is enabled', () => { const rootState = { featureFlags: { releaseShowPage: true } }; const updatedState = merge({}, state, { releasesPagePath: 'path/to/releases/page', diff --git a/spec/frontend/releases/stores/modules/detail/mutations_spec.js b/spec/frontend/releases/stores/modules/detail/mutations_spec.js index cb5a1880b0c..9d4f78be327 100644 --- a/spec/frontend/releases/stores/modules/detail/mutations_spec.js +++ b/spec/frontend/releases/stores/modules/detail/mutations_spec.js @@ -1,10 +1,3 @@ -/* eslint-disable jest/valid-describe */ -/* - * ESLint disable directive ↑ can be removed once - * https://github.com/jest-community/eslint-plugin-jest/issues/203 - * is resolved - */ - import createState from '~/releases/stores/modules/detail/state'; import mutations from '~/releases/stores/modules/detail/mutations'; import * as types from '~/releases/stores/modules/detail/mutation_types'; @@ -27,6 +20,7 @@ describe('Release detail mutations', () => { release = convertObjectPropsToCamelCase(originalRelease); }); + // eslint-disable-next-line jest/valid-describe describe(types.REQUEST_RELEASE, () => { it('set state.isFetchingRelease to true', () => { mutations[types.REQUEST_RELEASE](state); @@ -35,6 +29,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.RECEIVE_RELEASE_SUCCESS, () => { it('handles a successful response from the server', () => { mutations[types.RECEIVE_RELEASE_SUCCESS](state, release); @@ -49,6 +44,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.RECEIVE_RELEASE_ERROR, () => { it('handles an unsuccessful response from the server', () => { const error = { message: 'An error occurred!' }; @@ -62,6 +58,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.UPDATE_RELEASE_TITLE, () => { it("updates the release's title", () => { state.release = release; @@ -72,6 +69,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.UPDATE_RELEASE_NOTES, () => { it("updates the release's notes", () => { state.release = release; @@ -82,6 +80,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.REQUEST_UPDATE_RELEASE, () => { it('set state.isUpdatingRelease to true', () => { mutations[types.REQUEST_UPDATE_RELEASE](state); @@ -90,6 +89,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.RECEIVE_UPDATE_RELEASE_SUCCESS, () => { it('handles a successful response from the server', () => { mutations[types.RECEIVE_UPDATE_RELEASE_SUCCESS](state, release); @@ -100,6 +100,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.RECEIVE_UPDATE_RELEASE_ERROR, () => { it('handles an unsuccessful response from the server', () => { const error = { message: 'An error occurred!' }; @@ -111,6 +112,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.ADD_EMPTY_ASSET_LINK, () => { it('adds a new, empty link object to the release', () => { state.release = release; @@ -130,6 +132,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.UPDATE_ASSET_LINK_URL, () => { it('updates an asset link with a new URL', () => { state.release = release; @@ -145,6 +148,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.UPDATE_ASSET_LINK_NAME, () => { it('updates an asset link with a new name', () => { state.release = release; @@ -160,6 +164,7 @@ describe('Release detail mutations', () => { }); }); + // eslint-disable-next-line jest/valid-describe describe(types.REMOVE_ASSET_LINK, () => { it('removes an asset link from the release', () => { state.release = release; diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js index 962950ec96c..5dd9ea86221 100644 --- a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js +++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js @@ -48,7 +48,7 @@ describe('submitContentChanges', () => { it('notifies error when branch could not be created', () => { Api.createBranch.mockRejectedValueOnce(); - expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges({ username, projectId })).rejects.toThrow( SUBMIT_CHANGES_BRANCH_ERROR, ); }); @@ -72,7 +72,7 @@ describe('submitContentChanges', () => { it('notifies error when content could not be committed', () => { Api.commitMultiple.mockRejectedValueOnce(); - expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges({ username, projectId })).rejects.toThrow( SUBMIT_CHANGES_COMMIT_ERROR, ); }); @@ -93,7 +93,7 @@ describe('submitContentChanges', () => { it('notifies error when merge request could not be created', () => { Api.createProjectMergeRequest.mockRejectedValueOnce(); - expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges({ username, projectId })).rejects.toThrow( SUBMIT_CHANGES_MERGE_REQUEST_ERROR, ); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js index e2d31a41e82..214eb239432 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js @@ -33,9 +33,32 @@ describe('DropdownButton', () => { wrapper.destroy(); }); + describe('methods', () => { + describe('handleButtonClick', () => { + it('calls action `toggleDropdownContents` and stops event propagation when `state.variant` is "standalone"', () => { + const event = { + stopPropagation: jest.fn(), + }; + wrapper = createComponent({ + ...mockConfig, + variant: 'standalone', + }); + + jest.spyOn(wrapper.vm, 'toggleDropdownContents'); + + wrapper.vm.handleButtonClick(event); + + expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled(); + expect(event.stopPropagation).toHaveBeenCalled(); + + wrapper.destroy(); + }); + }); + }); + describe('template', () => { it('renders component container element', () => { - expect(wrapper.is('gl-deprecated-button-stub')).toBe(true); + expect(wrapper.is('gl-button-stub')).toBe(true); }); it('renders button text element', () => { diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js index d7ca7ce30a9..04320a72be6 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js @@ -1,7 +1,7 @@ import Vuex from 'vuex'; import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { GlDeprecatedButton, GlIcon, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui'; +import { GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui'; import DropdownContentsCreateView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue'; import labelSelectModule from '~/vue_shared/components/sidebar/labels_select_vue/store'; @@ -127,12 +127,12 @@ describe('DropdownContentsCreateView', () => { it('renders dropdown back button element', () => { const backBtnEl = wrapper .find('.dropdown-title') - .findAll(GlDeprecatedButton) + .findAll(GlButton) .at(0); expect(backBtnEl.exists()).toBe(true); expect(backBtnEl.attributes('aria-label')).toBe('Go back'); - expect(backBtnEl.find(GlIcon).props('name')).toBe('arrow-left'); + expect(backBtnEl.props('icon')).toBe('arrow-left'); }); it('renders dropdown title element', () => { @@ -145,12 +145,12 @@ describe('DropdownContentsCreateView', () => { it('renders dropdown close button element', () => { const closeBtnEl = wrapper .find('.dropdown-title') - .findAll(GlDeprecatedButton) + .findAll(GlButton) .at(1); expect(closeBtnEl.exists()).toBe(true); expect(closeBtnEl.attributes('aria-label')).toBe('Close'); - expect(closeBtnEl.find(GlIcon).props('name')).toBe('close'); + expect(closeBtnEl.props('icon')).toBe('close'); }); it('renders label title input element', () => { @@ -192,7 +192,7 @@ describe('DropdownContentsCreateView', () => { it('renders create button element', () => { const createBtnEl = wrapper .find('.dropdown-actions') - .findAll(GlDeprecatedButton) + .findAll(GlButton) .at(0); expect(createBtnEl.exists()).toBe(true); @@ -213,7 +213,7 @@ describe('DropdownContentsCreateView', () => { it('renders cancel button element', () => { const cancelBtnEl = wrapper .find('.dropdown-actions') - .findAll(GlDeprecatedButton) + .findAll(GlButton) .at(1); expect(cancelBtnEl.exists()).toBe(true); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js index 3e6dbdb7ecb..951ee3c9b3d 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js @@ -1,7 +1,7 @@ import Vuex from 'vuex'; import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { GlDeprecatedButton, GlLoadingIcon, GlIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui'; +import { GlButton, GlLoadingIcon, GlIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui'; import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes'; import DropdownContentsLabelsView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue'; @@ -41,13 +41,19 @@ const createComponent = (initialState = mockConfig) => { describe('DropdownContentsLabelsView', () => { let wrapper; + let wrapperStandalone; beforeEach(() => { wrapper = createComponent(); + wrapperStandalone = createComponent({ + ...mockConfig, + variant: 'standalone', + }); }); afterEach(() => { wrapper.destroy(); + wrapperStandalone.destroy(); }); describe('computed', () => { @@ -165,13 +171,24 @@ describe('DropdownContentsLabelsView', () => { }); describe('handleLabelClick', () => { - it('calls action `updateSelectedLabels` with provided `label` param', () => { + beforeEach(() => { jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation(); + }); + it('calls action `updateSelectedLabels` with provided `label` param', () => { wrapper.vm.handleLabelClick(mockRegularLabel); expect(wrapper.vm.updateSelectedLabels).toHaveBeenCalledWith([mockRegularLabel]); }); + + it('calls action `toggleDropdownContents` when `state.allowMultiselect` is false', () => { + jest.spyOn(wrapper.vm, 'toggleDropdownContents'); + wrapper.vm.$store.state.allowMultiselect = false; + + wrapper.vm.handleLabelClick(mockRegularLabel); + + expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled(); + }); }); }); @@ -198,12 +215,15 @@ describe('DropdownContentsLabelsView', () => { expect(titleEl.text()).toBe('Assign labels'); }); + it('does not render dropdown title element when `state.variant` is "standalone"', () => { + expect(wrapperStandalone.find('.dropdown-title').exists()).toBe(false); + }); + it('renders dropdown close button element', () => { - const closeButtonEl = wrapper.find('.dropdown-title').find(GlDeprecatedButton); + const closeButtonEl = wrapper.find('.dropdown-title').find(GlButton); expect(closeButtonEl.exists()).toBe(true); - expect(closeButtonEl.find(GlIcon).exists()).toBe(true); - expect(closeButtonEl.find(GlIcon).props('name')).toBe('close'); + expect(closeButtonEl.props('icon')).toBe('close'); }); it('renders label search input element', () => { @@ -253,13 +273,36 @@ describe('DropdownContentsLabelsView', () => { }); it('renders footer list items', () => { - const createLabelBtn = wrapper.find('.dropdown-footer').find(GlDeprecatedButton); - const manageLabelsLink = wrapper.find('.dropdown-footer').find(GlLink); - - expect(createLabelBtn.exists()).toBe(true); - expect(createLabelBtn.text()).toBe('Create label'); + const createLabelLink = wrapper + .find('.dropdown-footer') + .findAll(GlLink) + .at(0); + const manageLabelsLink = wrapper + .find('.dropdown-footer') + .findAll(GlLink) + .at(1); + + expect(createLabelLink.exists()).toBe(true); + expect(createLabelLink.text()).toBe('Create label'); expect(manageLabelsLink.exists()).toBe(true); expect(manageLabelsLink.text()).toBe('Manage labels'); }); + + it('does not render "Create label" footer link when `state.allowLabelCreate` is `false`', () => { + wrapper.vm.$store.state.allowLabelCreate = false; + + return wrapper.vm.$nextTick(() => { + const createLabelLink = wrapper + .find('.dropdown-footer') + .findAll(GlLink) + .at(0); + + expect(createLabelLink.text()).not.toBe('Create label'); + }); + }); + + it('does not render footer list items when `state.variant` is "standalone"', () => { + expect(wrapperStandalone.find('.dropdown-footer').exists()).toBe(false); + }); }); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js index 126fd5438c4..ee4e9090e5d 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js @@ -89,6 +89,19 @@ describe('LabelsSelectRoot', () => { expect(wrapper.attributes('class')).toContain('labels-select-wrapper position-relative'); }); + it('renders component root element with CSS class `is-standalone` when `state.variant` is "standalone"', () => { + const wrapperStandalone = createComponent({ + ...mockConfig, + variant: 'standalone', + }); + + return wrapperStandalone.vm.$nextTick(() => { + expect(wrapperStandalone.classes()).toContain('is-standalone'); + + wrapperStandalone.destroy(); + }); + }); + it('renders `dropdown-value-collapsed` component when `allowLabelCreate` prop is `true`', () => { expect(wrapper.find(DropdownValueCollapsed).exists()).toBe(true); }); @@ -101,13 +114,16 @@ describe('LabelsSelectRoot', () => { const wrapperDropdownValue = createComponent(mockConfig, { default: 'None', }); + wrapperDropdownValue.vm.$store.state.showDropdownButton = false; - const valueComp = wrapperDropdownValue.find(DropdownValue); + return wrapperDropdownValue.vm.$nextTick(() => { + const valueComp = wrapperDropdownValue.find(DropdownValue); - expect(valueComp.exists()).toBe(true); - expect(valueComp.text()).toBe('None'); + expect(valueComp.exists()).toBe(true); + expect(valueComp.text()).toBe('None'); - wrapperDropdownValue.destroy(); + wrapperDropdownValue.destroy(); + }); }); it('renders `dropdown-button` component when `showDropdownButton` prop is `true`', () => { diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js index e50771385dc..e1008d13fc2 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js @@ -30,8 +30,10 @@ export const mockConfig = { allowLabelEdit: true, allowLabelCreate: true, allowScopedLabels: true, + allowMultiselect: true, labelsListTitle: 'Assign labels', labelsCreateTitle: 'Create label', + variant: 'sidebar', dropdownOnly: false, selectedLabels: [mockRegularLabel, mockScopedLabel], labelsSelectInProgress: false, diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js index bfceaa0828b..b866117efcf 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js @@ -5,19 +5,25 @@ describe('LabelsSelect Getters', () => { it('returns string "Label" when state.labels has no selected labels', () => { const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; - expect(getters.dropdownButtonText({ labels })).toBe('Label'); + expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe( + 'Label', + ); }); it('returns label title when state.labels has only 1 label', () => { const labels = [{ id: 1, title: 'Foobar', set: true }]; - expect(getters.dropdownButtonText({ labels })).toBe('Foobar'); + expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe( + 'Foobar', + ); }); it('returns first label title and remaining labels count when state.labels has more than 1 label', () => { const labels = [{ id: 1, title: 'Foo', set: true }, { id: 2, title: 'Bar', set: true }]; - expect(getters.dropdownButtonText({ labels })).toBe('Foo +1 more'); + expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe( + 'Foo +1 more', + ); }); }); @@ -28,4 +34,16 @@ describe('LabelsSelect Getters', () => { expect(getters.selectedLabelsList({ selectedLabels })).toEqual([1, 2, 3, 4]); }); }); + + describe('isDropdownVariantSidebar', () => { + it('returns `true` when `state.variant` is "sidebar"', () => { + expect(getters.isDropdownVariantSidebar({ variant: 'sidebar' })).toBe(true); + }); + }); + + describe('isDropdownVariantStandalone', () => { + it('returns `true` when `state.variant` is "standalone"', () => { + expect(getters.isDropdownVariantStandalone({ variant: 'standalone' })).toBe(true); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js index f6ca98fcc71..3031df3362f 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js @@ -29,6 +29,7 @@ describe('LabelsSelect Mutations', () => { const state = { dropdownOnly: false, showDropdownButton: false, + variant: 'sidebar', }; mutations[types.TOGGLE_DROPDOWN_CONTENTS](state); @@ -154,10 +155,27 @@ describe('LabelsSelect Mutations', () => { describe(`${types.UPDATE_SELECTED_LABELS}`, () => { const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; - it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param', () => { + it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param when `state.allowMultiselect` is `true`', () => { const updatedLabelIds = [2, 4]; const state = { labels, + allowMultiselect: true, + }; + mutations[types.UPDATE_SELECTED_LABELS](state, { labels }); + + state.labels.forEach(label => { + if (updatedLabelIds.includes(label.id)) { + expect(label.touched).toBe(true); + expect(label.set).toBe(true); + } + }); + }); + + it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param when `state.allowMultiselect` is `false`', () => { + const updatedLabelIds = [2]; + const state = { + labels, + allowMultiselect: false, }; mutations[types.UPDATE_SELECTED_LABELS](state, { labels }); diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb index 33c1afad59f..ae1697fb7e6 100644 --- a/spec/models/timelog_spec.rb +++ b/spec/models/timelog_spec.rb @@ -56,12 +56,12 @@ RSpec.describe Timelog do end end - describe 'between_dates' do - it 'returns collection of timelogs within given dates' do + describe 'between_times' do + it 'returns collection of timelogs within given times' do create(:timelog, spent_at: 65.days.ago) timelog1 = create(:timelog, spent_at: 15.days.ago) timelog2 = create(:timelog, spent_at: 5.days.ago) - timelogs = described_class.between_dates(20.days.ago, 1.day.ago) + timelogs = described_class.between_times(20.days.ago, 1.day.ago) expect(timelogs).to contain_exactly(timelog1, timelog2) end |