From 682360490629376e2ec07d737c7d7dbfdaaeeab7 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 20 Dec 2019 18:07:53 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- spec/frontend/__mocks__/@gitlab/ui.js | 19 +++ spec/frontend/boards/issue_card_spec.js | 8 +- .../diffs/components/compare_versions_spec.js | 2 +- .../diffs/components/diff_file_header_spec.js | 2 +- .../environments/environment_monitoring_spec.js | 2 +- .../frontend/environments/environment_stop_spec.js | 2 +- .../environment_terminal_button_spec.js | 2 +- spec/frontend/ide/stores/actions/file_spec.js | 52 +++--- spec/frontend/ide/stores/mutations/file_spec.js | 174 +++++++++++++++++---- .../issuable_suggestions/components/item_spec.js | 2 +- .../issuables_list/components/issuable_spec.js | 4 +- .../discussion_jump_to_next_button_spec.js.snap | 3 +- .../pipelines/graph/action_component_spec.js | 4 +- spec/frontend/pipelines/graph/job_item_spec.js | 12 +- .../pipelines/graph/linked_pipeline_spec.js | 2 +- spec/frontend/pipelines/pipeline_url_spec.js | 4 +- .../__snapshots__/project_empty_state_spec.js.snap | 9 +- .../list/components/evidence_block_spec.js | 6 +- .../release_block_milestone_info_spec.js | 2 +- .../releases/list/components/release_block_spec.js | 2 +- .../__snapshots__/last_commit_spec.js.snap | 6 +- spec/frontend/sidebar/assignees_spec.js | 2 +- .../assignees/assignee_avatar_link_spec.js | 2 +- .../assignees/collapsed_assignee_list_spec.js | 2 +- .../components/changed_file_icon_spec.js | 4 +- .../vue_shared/components/clipboard_button_spec.js | 2 +- spec/frontend/vue_shared/components/commit_spec.js | 4 +- .../components/issue/issue_assignees_spec.js | 2 +- .../vue_shared/components/time_ago_tooltip_spec.js | 2 +- .../user_avatar/user_avatar_image_spec.js | 2 +- .../user_avatar/user_avatar_link_spec.js | 6 +- 31 files changed, 233 insertions(+), 114 deletions(-) create mode 100644 spec/frontend/__mocks__/@gitlab/ui.js (limited to 'spec/frontend') diff --git a/spec/frontend/__mocks__/@gitlab/ui.js b/spec/frontend/__mocks__/@gitlab/ui.js new file mode 100644 index 00000000000..ef97cb11424 --- /dev/null +++ b/spec/frontend/__mocks__/@gitlab/ui.js @@ -0,0 +1,19 @@ +export * from '@gitlab/ui'; + +/** + * The @gitlab/ui tooltip directive requires awkward and distracting set up in tests + * for components that use it (e.g., `attachToDocument: true` and `sync: true` passed + * to the `mount` helper from `vue-test-utils`). + * + * This mock decouples those tests from the implementation, removing the need to set + * them up specially just for these tooltips. + */ +export const GlTooltipDirective = { + bind() {}, +}; + +export const GlTooltip = { + render(h) { + return h('div', this.$attrs, this.$slots.default); + }, +}; diff --git a/spec/frontend/boards/issue_card_spec.js b/spec/frontend/boards/issue_card_spec.js index c7ab477c0af..4a0a3497620 100644 --- a/spec/frontend/boards/issue_card_spec.js +++ b/spec/frontend/boards/issue_card_spec.js @@ -267,17 +267,13 @@ describe('Issue card component', () => { }); it('renders label', () => { - const nodes = wrapper - .findAll('.badge') - .wrappers.map(label => label.attributes('data-original-title')); + const nodes = wrapper.findAll('.badge').wrappers.map(label => label.attributes('title')); expect(nodes.includes(label1.description)).toBe(true); }); it('sets label description as title', () => { - expect(wrapper.find('.badge').attributes('data-original-title')).toContain( - label1.description, - ); + expect(wrapper.find('.badge').attributes('title')).toContain(label1.description); }); it('sets background color of button', () => { diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js index 9900fcdb6e1..dcce6f1fa7a 100644 --- a/spec/frontend/diffs/components/compare_versions_spec.js +++ b/spec/frontend/diffs/components/compare_versions_spec.js @@ -49,7 +49,7 @@ describe('CompareVersions', () => { const treeListBtn = wrapper.find('.js-toggle-tree-list'); expect(treeListBtn.exists()).toBe(true); - expect(treeListBtn.attributes('data-original-title')).toBe('Hide file browser'); + expect(treeListBtn.attributes('title')).toBe('Hide file browser'); expect(treeListBtn.findAll(Icon).length).not.toBe(0); expect(treeListBtn.find(Icon).props('name')).toBe('collapse-left'); }); diff --git a/spec/frontend/diffs/components/diff_file_header_spec.js b/spec/frontend/diffs/components/diff_file_header_spec.js index 48fd6dd6f58..f2d07d3d4b2 100644 --- a/spec/frontend/diffs/components/diff_file_header_spec.js +++ b/spec/frontend/diffs/components/diff_file_header_spec.js @@ -329,7 +329,7 @@ describe('DiffFileHeader component', () => { addMergeRequestButtons: true, }); expect(findViewFileButton().attributes('href')).toBe(viewPath); - expect(findViewFileButton().attributes('data-original-title')).toEqual( + expect(findViewFileButton().attributes('title')).toEqual( `View file @ ${diffFile.content_sha.substr(0, 8)}`, ); }); diff --git a/spec/frontend/environments/environment_monitoring_spec.js b/spec/frontend/environments/environment_monitoring_spec.js index 8e67f799dc0..22241d5120b 100644 --- a/spec/frontend/environments/environment_monitoring_spec.js +++ b/spec/frontend/environments/environment_monitoring_spec.js @@ -33,7 +33,7 @@ describe('Monitoring Component', () => { it('should render a link to environment monitoring page', () => { expect(wrapper.attributes('href')).toEqual(monitoringUrl); expect(findIconsByName('chart').length).toBe(1); - expect(wrapper.attributes('data-original-title')).toBe('Monitoring'); + expect(wrapper.attributes('title')).toBe('Monitoring'); expect(wrapper.attributes('aria-label')).toBe('Monitoring'); }); }); diff --git a/spec/frontend/environments/environment_stop_spec.js b/spec/frontend/environments/environment_stop_spec.js index ab714728311..be029d48a56 100644 --- a/spec/frontend/environments/environment_stop_spec.js +++ b/spec/frontend/environments/environment_stop_spec.js @@ -29,7 +29,7 @@ describe('Stop Component', () => { it('should render a button to stop the environment', () => { expect(findButton().exists()).toBe(true); - expect(wrapper.attributes('data-original-title')).toEqual('Stop environment'); + expect(wrapper.attributes('title')).toEqual('Stop environment'); }); it('emits requestStopEnvironment in the event hub when button is clicked', () => { diff --git a/spec/frontend/environments/environment_terminal_button_spec.js b/spec/frontend/environments/environment_terminal_button_spec.js index 9aa2b82736c..058940c0e98 100644 --- a/spec/frontend/environments/environment_terminal_button_spec.js +++ b/spec/frontend/environments/environment_terminal_button_spec.js @@ -25,7 +25,7 @@ describe('Stop Component', () => { it('should render a link to open a web terminal with the provided path', () => { expect(wrapper.is('a')).toBe(true); - expect(wrapper.attributes('data-original-title')).toBe('Terminal'); + expect(wrapper.attributes('title')).toBe('Terminal'); expect(wrapper.attributes('aria-label')).toBe('Terminal'); expect(wrapper.attributes('href')).toBe(terminalPath); }); diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js index 283ea266821..e9a657ffbfc 100644 --- a/spec/frontend/ide/stores/actions/file_spec.js +++ b/spec/frontend/ide/stores/actions/file_spec.js @@ -1,20 +1,20 @@ import Vue from 'vue'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; -import store from '~/ide/stores'; +import { createStore } from '~/ide/stores'; import * as actions from '~/ide/stores/actions/file'; import * as types from '~/ide/stores/mutation_types'; import service from '~/ide/services'; import router from '~/ide/ide_router'; import eventHub from '~/ide/eventhub'; -import { file, resetStore } from '../../helpers'; -import testAction from '../../../helpers/vuex_action_helper'; +import { file } from '../../helpers'; const RELATIVE_URL_ROOT = '/gitlab'; describe('IDE store file actions', () => { let mock; let originalGon; + let store; beforeEach(() => { mock = new MockAdapter(axios); @@ -24,12 +24,15 @@ describe('IDE store file actions', () => { relative_url_root: RELATIVE_URL_ROOT, }; + store = createStore(); + + jest.spyOn(store, 'commit'); + jest.spyOn(store, 'dispatch'); jest.spyOn(router, 'push').mockImplementation(() => {}); }); afterEach(() => { mock.restore(); - resetStore(store); window.gon = originalGon; }); @@ -663,30 +666,33 @@ describe('IDE store file actions', () => { }); describe('stageChange', () => { - it('calls STAGE_CHANGE with file path', done => { - testAction( - actions.stageChange, - 'path', - store.state, - [ - { type: types.STAGE_CHANGE, payload: 'path' }, - { type: types.SET_LAST_COMMIT_MSG, payload: '' }, - ], - [], - done, + it('calls STAGE_CHANGE with file path', () => { + const f = { ...file('path'), content: 'old' }; + + store.state.entries[f.path] = f; + + actions.stageChange(store, 'path'); + + expect(store.commit).toHaveBeenCalledWith( + types.STAGE_CHANGE, + expect.objectContaining({ path: 'path' }), ); + expect(store.commit).toHaveBeenCalledWith(types.SET_LAST_COMMIT_MSG, ''); }); }); describe('unstageChange', () => { - it('calls UNSTAGE_CHANGE with file path', done => { - testAction( - actions.unstageChange, - 'path', - store.state, - [{ type: types.UNSTAGE_CHANGE, payload: 'path' }], - [], - done, + it('calls UNSTAGE_CHANGE with file path', () => { + const f = { ...file('path'), content: 'old' }; + + store.state.entries[f.path] = f; + store.state.stagedFiles.push({ f, content: 'new' }); + + actions.unstageChange(store, 'path'); + + expect(store.commit).toHaveBeenCalledWith( + types.UNSTAGE_CHANGE, + expect.objectContaining({ path: 'path' }), ); }); }); diff --git a/spec/frontend/ide/stores/mutations/file_spec.js b/spec/frontend/ide/stores/mutations/file_spec.js index 91506c1b46c..8cb386d27e5 100644 --- a/spec/frontend/ide/stores/mutations/file_spec.js +++ b/spec/frontend/ide/stores/mutations/file_spec.js @@ -1,14 +1,16 @@ import mutations from '~/ide/stores/mutations/file'; -import state from '~/ide/stores/state'; +import { createStore } from '~/ide/stores'; import { FILE_VIEW_MODE_PREVIEW } from '~/ide/constants'; import { file } from '../../helpers'; describe('IDE store file mutations', () => { let localState; + let localStore; let localFile; beforeEach(() => { - localState = state(); + localStore = createStore(); + localState = localStore.state; localFile = { ...file(), type: 'blob' }; localState.entries[localFile.path] = localFile; @@ -333,44 +335,154 @@ describe('IDE store file mutations', () => { }); }); - describe('STAGE_CHANGE', () => { - beforeEach(() => { - mutations.STAGE_CHANGE(localState, localFile.path); - }); + describe.each` + mutationName | mutation | addedTo | removedFrom | staged | changedFilesCount | stagedFilesCount + ${'STAGE_CHANGE'} | ${mutations.STAGE_CHANGE} | ${'stagedFiles'} | ${'changedFiles'} | ${true} | ${0} | ${1} + ${'UNSTAGE_CHANGE'} | ${mutations.UNSTAGE_CHANGE} | ${'changedFiles'} | ${'stagedFiles'} | ${false} | ${1} | ${0} + `( + '$mutationName', + ({ mutation, changedFilesCount, removedFrom, addedTo, staged, stagedFilesCount }) => { + let unstagedFile; + let stagedFile; + + beforeEach(() => { + unstagedFile = { + ...file('file'), + type: 'blob', + raw: 'original content', + content: 'changed content', + }; + + stagedFile = { + ...unstagedFile, + content: 'staged content', + staged: true, + }; + + localState.changedFiles.push(unstagedFile); + localState.stagedFiles.push(stagedFile); + localState.entries[unstagedFile.path] = unstagedFile; + }); - it('adds file into stagedFiles array', () => { - expect(localState.stagedFiles.length).toBe(1); - expect(localState.stagedFiles[0]).toEqual(localFile); - }); + it('removes all changes of a file if staged and unstaged change contents are equal', () => { + unstagedFile.content = 'original content'; - it('updates stagedFile if it is already staged', () => { - localFile.raw = 'testing 123'; + mutation(localState, { + path: unstagedFile.path, + diffInfo: localStore.getters.getDiffInfo(unstagedFile.path), + }); - mutations.STAGE_CHANGE(localState, localFile.path); + expect(localState.entries.file).toEqual( + expect.objectContaining({ + content: 'original content', + staged: false, + changed: false, + }), + ); - expect(localState.stagedFiles.length).toBe(1); - expect(localState.stagedFiles[0].raw).toEqual('testing 123'); - }); - }); + expect(localState.stagedFiles.length).toBe(0); + expect(localState.changedFiles.length).toBe(0); + }); - describe('UNSTAGE_CHANGE', () => { - let f; + it('removes all changes of a file if a file is deleted and a new file with same content is added', () => { + stagedFile.deleted = true; + unstagedFile.tempFile = true; + unstagedFile.content = 'original content'; - beforeEach(() => { - f = { ...file(), type: 'blob', staged: true }; + mutation(localState, { + path: unstagedFile.path, + diffInfo: localStore.getters.getDiffInfo(unstagedFile.path), + }); - localState.stagedFiles.push(f); - localState.changedFiles.push(f); - localState.entries[f.path] = f; - }); + expect(localState.stagedFiles.length).toBe(0); + expect(localState.changedFiles.length).toBe(0); - it('removes from stagedFiles array', () => { - mutations.UNSTAGE_CHANGE(localState, f.path); + expect(localState.entries.file).toEqual( + expect.objectContaining({ + content: 'original content', + deleted: false, + tempFile: false, + }), + ); + }); - expect(localState.stagedFiles.length).toBe(0); - expect(localState.changedFiles.length).toBe(1); - }); - }); + it('merges deleted and added file into a changed file if the contents differ', () => { + stagedFile.deleted = true; + unstagedFile.tempFile = true; + unstagedFile.content = 'hello'; + + mutation(localState, { + path: unstagedFile.path, + diffInfo: localStore.getters.getDiffInfo(unstagedFile.path), + }); + + expect(localState.stagedFiles.length).toBe(stagedFilesCount); + expect(localState.changedFiles.length).toBe(changedFilesCount); + + expect(unstagedFile).toEqual( + expect.objectContaining({ + content: 'hello', + staged, + deleted: false, + tempFile: false, + changed: true, + }), + ); + }); + + it('does not remove file from stagedFiles and changedFiles if the file was renamed, even if the contents are equal', () => { + unstagedFile.content = 'original content'; + unstagedFile.prevPath = 'old_file'; + + mutation(localState, { + path: unstagedFile.path, + diffInfo: localStore.getters.getDiffInfo(unstagedFile.path), + }); + + expect(localState.entries.file).toEqual( + expect.objectContaining({ + content: 'original content', + staged, + changed: false, + prevPath: 'old_file', + }), + ); + + expect(localState.stagedFiles.length).toBe(stagedFilesCount); + expect(localState.changedFiles.length).toBe(changedFilesCount); + }); + + it(`removes file from ${removedFrom} array and adds it into ${addedTo} array`, () => { + localState.stagedFiles.length = 0; + + mutation(localState, { + path: unstagedFile.path, + diffInfo: localStore.getters.getDiffInfo(unstagedFile.path), + }); + + expect(localState.stagedFiles.length).toBe(stagedFilesCount); + expect(localState.changedFiles.length).toBe(changedFilesCount); + + const f = localState.stagedFiles[0] || localState.changedFiles[0]; + expect(f).toEqual(unstagedFile); + }); + + it(`updates file in ${addedTo} array if it is was already present in it`, () => { + unstagedFile.raw = 'testing 123'; + + mutation(localState, { + path: unstagedFile.path, + diffInfo: localStore.getters.getDiffInfo(unstagedFile.path), + }); + + expect(localState.stagedFiles.length).toBe(stagedFilesCount); + expect(localState.changedFiles.length).toBe(changedFilesCount); + + const f = localState.stagedFiles[0] || localState.changedFiles[0]; + expect(f.raw).toEqual('testing 123'); + }); + }, + ); describe('TOGGLE_FILE_CHANGED', () => { it('updates file changed status', () => { diff --git a/spec/frontend/issuable_suggestions/components/item_spec.js b/spec/frontend/issuable_suggestions/components/item_spec.js index 10fba238506..eeea8960658 100644 --- a/spec/frontend/issuable_suggestions/components/item_spec.js +++ b/spec/frontend/issuable_suggestions/components/item_spec.js @@ -135,7 +135,7 @@ describe('Issuable suggestions suggestion component', () => { const icon = vm.find(Icon); expect(icon.props('name')).toBe('eye-slash'); - expect(icon.attributes('data-original-title')).toBe('Confidential'); + expect(icon.attributes('title')).toBe('Confidential'); }); }); }); diff --git a/spec/frontend/issuables_list/components/issuable_spec.js b/spec/frontend/issuables_list/components/issuable_spec.js index b6851a0e24c..b4d0bd47d65 100644 --- a/spec/frontend/issuables_list/components/issuable_spec.js +++ b/spec/frontend/issuables_list/components/issuable_spec.js @@ -70,7 +70,7 @@ describe('Issuable component', () => { const findTaskStatus = () => wrapper.find('.task-status'); const findOpenedAgoContainer = () => wrapper.find({ ref: 'openedAgoByContainer' }); const findMilestone = () => wrapper.find('.js-milestone'); - const findMilestoneTooltip = () => findMilestone().attributes('data-original-title'); + const findMilestoneTooltip = () => findMilestone().attributes('title'); const findDueDate = () => wrapper.find('.js-due-date'); const findLabelContainer = () => wrapper.find('.js-labels'); const findLabelLinks = () => findLabelContainer().findAll(GlLink); @@ -240,7 +240,7 @@ describe('Issuable component', () => { const labels = findLabelLinks().wrappers.map(label => ({ href: label.attributes('href'), text: label.text(), - tooltip: label.find('span').attributes('data-original-title'), + tooltip: label.find('span').attributes('title'), })); const expected = testLabels.map(label => ({ diff --git a/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap b/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap index b29d093130a..1e466f266ed 100644 --- a/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap +++ b/spec/frontend/notes/components/__snapshots__/discussion_jump_to_next_button_spec.js.snap @@ -7,8 +7,7 @@ exports[`JumpToNextDiscussionButton matches the snapshot 1`] = ` >