diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-20 12:26:25 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-20 12:26:25 +0000 |
commit | a09983ae35713f5a2bbb100981116d31ce99826e (patch) | |
tree | 2ee2af7bd104d57086db360a7e6d8c9d5d43667a /spec/frontend/ide/components | |
parent | 18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff) | |
download | gitlab-ce-a09983ae35713f5a2bbb100981116d31ce99826e.tar.gz |
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'spec/frontend/ide/components')
3 files changed, 95 insertions, 28 deletions
diff --git a/spec/frontend/ide/components/ide_status_list_spec.js b/spec/frontend/ide/components/ide_status_list_spec.js index 847464ed806..fed61233e55 100644 --- a/spec/frontend/ide/components/ide_status_list_spec.js +++ b/spec/frontend/ide/components/ide_status_list_spec.js @@ -1,5 +1,6 @@ import Vuex from 'vuex'; import { createLocalVue, shallowMount } from '@vue/test-utils'; +import { GlLink } from '@gitlab/ui'; import IdeStatusList from '~/ide/components/ide_status_list.vue'; import TerminalSyncStatusSafe from '~/ide/components/terminal_sync/terminal_sync_status_safe.vue'; @@ -9,6 +10,7 @@ const TEST_FILE = { editorColumn: 23, fileLanguage: 'markdown', content: 'abc\nndef', + permalink: '/lorem.md', }; const localVue = createLocalVue(); @@ -19,6 +21,7 @@ describe('ide/components/ide_status_list', () => { let store; let wrapper; + const findLink = () => wrapper.find(GlLink); const createComponent = (options = {}) => { store = new Vuex.Store({ getters: { @@ -51,8 +54,9 @@ describe('ide/components/ide_status_list', () => { createComponent(); }); - it('shows file name', () => { - expect(wrapper.text()).toContain(TEST_FILE.name); + it('shows a link to the file that contains the file name', () => { + expect(findLink().attributes('href')).toBe(TEST_FILE.permalink); + expect(findLink().text()).toBe(TEST_FILE.name); }); it('shows file eol', () => { diff --git a/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap b/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap index bdd3d439fd4..dbfacb98813 100644 --- a/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap +++ b/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap @@ -2,7 +2,7 @@ exports[`IDE pipeline stage renders stage details & icon 1`] = ` <div - class="ide-stage card prepend-top-default" + class="ide-stage card gl-mt-3" > <div class="card-header" diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js index 4967434dfd7..a4336b8f2eb 100644 --- a/spec/frontend/ide/components/repo_editor_spec.js +++ b/spec/frontend/ide/components/repo_editor_spec.js @@ -4,19 +4,25 @@ import MockAdapter from 'axios-mock-adapter'; import '~/behaviors/markdown/render_gfm'; import { Range } from 'monaco-editor'; import axios from '~/lib/utils/axios_utils'; +import service from '~/ide/services'; import { createStoreOptions } from '~/ide/stores'; import RepoEditor from '~/ide/components/repo_editor.vue'; import Editor from '~/ide/lib/editor'; -import { leftSidebarViews, FILE_VIEW_MODE_EDITOR, FILE_VIEW_MODE_PREVIEW } from '~/ide/constants'; +import { + leftSidebarViews, + FILE_VIEW_MODE_EDITOR, + FILE_VIEW_MODE_PREVIEW, + viewerTypes, +} from '~/ide/constants'; import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { file } from '../helpers'; import { exampleConfigs, exampleFiles } from '../lib/editorconfig/mock_data'; +import waitUsingRealTimer from 'helpers/wait_using_real_timer'; describe('RepoEditor', () => { let vm; let store; - let mockActions; const waitForEditorSetup = () => new Promise(resolve => { @@ -30,6 +36,10 @@ describe('RepoEditor', () => { vm = createComponentWithStore(Vue.extend(RepoEditor), store, { file: store.state.openFiles[0], }); + + jest.spyOn(vm, 'getFileData').mockResolvedValue(); + jest.spyOn(vm, 'getRawFileData').mockResolvedValue(); + vm.$mount(); }; @@ -43,21 +53,12 @@ describe('RepoEditor', () => { }; beforeEach(() => { - mockActions = { - getFileData: jest.fn().mockResolvedValue(), - getRawFileData: jest.fn().mockResolvedValue(), - }; - const f = { ...file(), viewMode: FILE_VIEW_MODE_EDITOR, }; const storeOptions = createStoreOptions(); - storeOptions.actions = { - ...storeOptions.actions, - ...mockActions, - }; store = new Vuex.Store(storeOptions); f.active = true; @@ -438,7 +439,7 @@ describe('RepoEditor', () => { vm.initEditor(); vm.$nextTick() .then(() => { - expect(mockActions.getFileData).not.toHaveBeenCalled(); + expect(vm.getFileData).not.toHaveBeenCalled(); }) .then(done) .catch(done.fail); @@ -449,10 +450,11 @@ describe('RepoEditor', () => { vm.file.raw = ''; vm.initEditor(); + vm.$nextTick() .then(() => { - expect(mockActions.getFileData).toHaveBeenCalled(); - expect(mockActions.getRawFileData).toHaveBeenCalled(); + expect(vm.getFileData).toHaveBeenCalled(); + expect(vm.getRawFileData).toHaveBeenCalled(); }) .then(done) .catch(done.fail); @@ -464,8 +466,8 @@ describe('RepoEditor', () => { vm.initEditor(); vm.$nextTick() .then(() => { - expect(mockActions.getFileData).not.toHaveBeenCalled(); - expect(mockActions.getRawFileData).not.toHaveBeenCalled(); + expect(vm.getFileData).not.toHaveBeenCalled(); + expect(vm.getRawFileData).not.toHaveBeenCalled(); expect(vm.editor.createInstance).not.toHaveBeenCalled(); }) .then(done) @@ -526,6 +528,63 @@ describe('RepoEditor', () => { }); }); + describe('populates editor with the fetched content', () => { + beforeEach(() => { + vm.getRawFileData.mockRestore(); + }); + + const createRemoteFile = name => ({ + ...file(name), + tmpFile: false, + }); + + it('after switching viewer from edit to diff', async () => { + jest.spyOn(service, 'getRawFileData').mockImplementation(async () => { + expect(vm.file.loading).toBe(true); + + // switching from edit to diff mode usually triggers editor initialization + store.state.viewer = viewerTypes.diff; + + // we delay returning the file to make sure editor doesn't initialize before we fetch file content + await waitUsingRealTimer(30); + return 'rawFileData123\n'; + }); + + const f = createRemoteFile('newFile'); + Vue.set(store.state.entries, f.path, f); + + vm.file = f; + + await waitForEditorSetup(); + expect(vm.model.getModel().getValue()).toBe('rawFileData123\n'); + }); + + it('after opening multiple files at the same time', async () => { + const fileA = createRemoteFile('fileA'); + const fileB = createRemoteFile('fileB'); + Vue.set(store.state.entries, fileA.path, fileA); + Vue.set(store.state.entries, fileB.path, fileB); + + jest + .spyOn(service, 'getRawFileData') + .mockImplementationOnce(async () => { + // opening fileB while the content of fileA is still being fetched + vm.file = fileB; + return 'fileA-rawContent\n'; + }) + .mockImplementationOnce(async () => { + // we delay returning fileB content to make sure the editor doesn't initialize prematurely + await waitUsingRealTimer(30); + return 'fileB-rawContent\n'; + }); + + vm.file = fileA; + + await waitForEditorSetup(); + expect(vm.model.getModel().getValue()).toBe('fileB-rawContent\n'); + }); + }); + describe('onPaste', () => { const setFileName = name => { Vue.set(vm, 'file', { @@ -557,6 +616,11 @@ describe('RepoEditor', () => { }); }); + // Pasting an image does a lot of things like using the FileReader API, + // so, waitForPromises isn't very reliable (and causes a flaky spec) + // Read more about state.watch: https://vuex.vuejs.org/api/#watch + const waitForFileContentChange = () => watchState(s => s.entries['foo/bar.md'].content); + beforeEach(() => { setFileName('bar.md'); @@ -573,13 +637,15 @@ describe('RepoEditor', () => { // set cursor to line 2, column 1 vm.editor.instance.setSelection(new Range(2, 1, 2, 1)); vm.editor.instance.focus(); + + jest.spyOn(vm.editor.instance, 'hasTextFocus').mockReturnValue(true); }); }); it('adds an image entry to the same folder for a pasted image in a markdown file', () => { pasteImage(); - return waitForPromises().then(() => { + return waitForFileContentChange().then(() => { expect(vm.$store.state.entries['foo/foo.png']).toMatchObject({ path: 'foo/foo.png', type: 'blob', @@ -593,10 +659,7 @@ describe('RepoEditor', () => { it("adds a markdown image tag to the file's contents", () => { pasteImage(); - // Pasting an image does a lot of things like using the FileReader API, - // so, waitForPromises isn't very reliable (and causes a flaky spec) - // Read more about state.watch: https://vuex.vuejs.org/api/#watch - return watchState(s => s.entries['foo/bar.md'].content).then(() => { + return waitForFileContentChange().then(() => { expect(vm.file.content).toBe('hello world\n![foo.png](./foo.png)'); }); }); @@ -629,8 +692,8 @@ describe('RepoEditor', () => { return waitForEditorSetup().then(() => { expect(vm.rules).toEqual(monacoRules); expect(vm.model.options).toMatchObject(monacoRules); - expect(mockActions.getFileData).not.toHaveBeenCalled(); - expect(mockActions.getRawFileData).not.toHaveBeenCalled(); + expect(vm.getFileData).not.toHaveBeenCalled(); + expect(vm.getRawFileData).not.toHaveBeenCalled(); }); }, ); @@ -646,13 +709,13 @@ describe('RepoEditor', () => { createComponent(); return waitForEditorSetup().then(() => { - expect(mockActions.getFileData.mock.calls.map(([, args]) => args)).toEqual([ + expect(vm.getFileData.mock.calls.map(([args]) => args)).toEqual([ { makeFileActive: false, path: 'foo/bar/baz/.editorconfig' }, { makeFileActive: false, path: 'foo/bar/.editorconfig' }, { makeFileActive: false, path: 'foo/.editorconfig' }, { makeFileActive: false, path: '.editorconfig' }, ]); - expect(mockActions.getRawFileData.mock.calls.map(([, args]) => args)).toEqual([ + expect(vm.getRawFileData.mock.calls.map(([args]) => args)).toEqual([ { path: 'foo/bar/baz/.editorconfig' }, { path: 'foo/bar/.editorconfig' }, { path: 'foo/.editorconfig' }, |