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 | |
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')
-rw-r--r-- | spec/frontend/ide/commit_icon_spec.js | 1 | ||||
-rw-r--r-- | spec/frontend/ide/components/ide_status_list_spec.js | 8 | ||||
-rw-r--r-- | spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap | 2 | ||||
-rw-r--r-- | spec/frontend/ide/components/repo_editor_spec.js | 113 | ||||
-rw-r--r-- | spec/frontend/ide/helpers.js | 1 | ||||
-rw-r--r-- | spec/frontend/ide/lib/editor_spec.js | 22 | ||||
-rw-r--r-- | spec/frontend/ide/services/index_spec.js | 6 | ||||
-rw-r--r-- | spec/frontend/ide/stores/actions/file_spec.js | 361 | ||||
-rw-r--r-- | spec/frontend/ide/stores/actions/merge_request_spec.js | 1 | ||||
-rw-r--r-- | spec/frontend/ide/stores/actions/tree_spec.js | 3 | ||||
-rw-r--r-- | spec/frontend/ide/utils_spec.js | 52 |
11 files changed, 335 insertions, 235 deletions
diff --git a/spec/frontend/ide/commit_icon_spec.js b/spec/frontend/ide/commit_icon_spec.js index 90b8e34497c..e4a7394b089 100644 --- a/spec/frontend/ide/commit_icon_spec.js +++ b/spec/frontend/ide/commit_icon_spec.js @@ -11,7 +11,6 @@ const createFile = (name = 'name', id = name, type = '', parent = null) => name, path: parent ? `${parent.path}/${name}` : name, parentPath: parent ? parent.path : '', - lastCommit: {}, }); describe('getCommitIconMap', () => { 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' }, diff --git a/spec/frontend/ide/helpers.js b/spec/frontend/ide/helpers.js index de839fa99ca..a9620d26313 100644 --- a/spec/frontend/ide/helpers.js +++ b/spec/frontend/ide/helpers.js @@ -30,7 +30,6 @@ export const file = (name = 'name', id = name, type = '', parent = null) => name, path: parent ? `${parent.path}/${name}` : name, parentPath: parent ? parent.path : '', - lastCommit: {}, }); export const createEntriesFromPaths = paths => diff --git a/spec/frontend/ide/lib/editor_spec.js b/spec/frontend/ide/lib/editor_spec.js index f5815771cdf..5f28309422d 100644 --- a/spec/frontend/ide/lib/editor_spec.js +++ b/spec/frontend/ide/lib/editor_spec.js @@ -199,6 +199,28 @@ describe('Multi-file editor library', () => { }); }); + describe('schemas', () => { + let originalGon; + + beforeEach(() => { + originalGon = window.gon; + window.gon = { features: { schemaLinting: true } }; + + delete Editor.editorInstance; + instance = Editor.create(); + }); + + afterEach(() => { + window.gon = originalGon; + }); + + it('registers custom schemas defined with Monaco', () => { + expect(monacoLanguages.yaml.yamlDefaults.diagnosticsOptions).toMatchObject({ + schemas: [{ fileMatch: ['*.gitlab-ci.yml'] }], + }); + }); + }); + describe('replaceSelectedText', () => { let model; let editor; diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js index 3cb6e064aa2..bc3f86702cf 100644 --- a/spec/frontend/ide/services/index_spec.js +++ b/spec/frontend/ide/services/index_spec.js @@ -2,7 +2,7 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import services from '~/ide/services'; import Api from '~/api'; -import gqClient from '~/ide/services/gql'; +import { query } from '~/ide/services/gql'; import { escapeFileUrl } from '~/lib/utils/url_utility'; import getUserPermissions from '~/ide/queries/getUserPermissions.query.graphql'; import { projectData } from '../mock_data'; @@ -207,12 +207,12 @@ describe('IDE services', () => { }, }; Api.project.mockReturnValue(Promise.resolve({ data: { ...projectData } })); - gqClient.query.mockReturnValue(Promise.resolve({ data: { project: gqlProjectData } })); + query.mockReturnValue(Promise.resolve({ data: { project: gqlProjectData } })); return services.getProjectData(TEST_NAMESPACE, TEST_PROJECT).then(response => { expect(response).toEqual({ data: { ...projectData, ...gqlProjectData } }); expect(Api.project).toHaveBeenCalledWith(TEST_PROJECT_ID); - expect(gqClient.query).toHaveBeenCalledWith({ + expect(query).toHaveBeenCalledWith({ query: getUserPermissions, variables: { projectPath: TEST_PROJECT_ID, diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js index e2dc7626c67..88e7a9fff36 100644 --- a/spec/frontend/ide/stores/actions/file_spec.js +++ b/spec/frontend/ide/stores/actions/file_spec.js @@ -51,35 +51,27 @@ describe('IDE store file actions', () => { store.state.entries[localFile.path] = localFile; }); - it('closes open files', done => { - store - .dispatch('closeFile', localFile) - .then(() => { - expect(localFile.opened).toBeFalsy(); - expect(localFile.active).toBeFalsy(); - expect(store.state.openFiles.length).toBe(0); - - done(); - }) - .catch(done.fail); + it('closes open files', () => { + return store.dispatch('closeFile', localFile).then(() => { + expect(localFile.opened).toBeFalsy(); + expect(localFile.active).toBeFalsy(); + expect(store.state.openFiles.length).toBe(0); + }); }); - it('closes file even if file has changes', done => { + it('closes file even if file has changes', () => { store.state.changedFiles.push(localFile); - store + return store .dispatch('closeFile', localFile) .then(Vue.nextTick) .then(() => { expect(store.state.openFiles.length).toBe(0); expect(store.state.changedFiles.length).toBe(1); - - done(); - }) - .catch(done.fail); + }); }); - it('closes file & opens next available file', done => { + it('closes file & opens next available file', () => { const f = { ...file('newOpenFile'), url: '/newOpenFile', @@ -88,31 +80,23 @@ describe('IDE store file actions', () => { store.state.openFiles.push(f); store.state.entries[f.path] = f; - store + return store .dispatch('closeFile', localFile) .then(Vue.nextTick) .then(() => { expect(router.push).toHaveBeenCalledWith(`/project${f.url}`); - - done(); - }) - .catch(done.fail); + }); }); - it('removes file if it pending', done => { + it('removes file if it pending', () => { store.state.openFiles.push({ ...localFile, pending: true, }); - store - .dispatch('closeFile', localFile) - .then(() => { - expect(store.state.openFiles.length).toBe(0); - - done(); - }) - .catch(done.fail); + return store.dispatch('closeFile', localFile).then(() => { + expect(store.state.openFiles.length).toBe(0); + }); }); }); @@ -264,61 +248,48 @@ describe('IDE store file actions', () => { ); }); - it('calls the service', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(service.getFileData).toHaveBeenCalledWith( - `${RELATIVE_URL_ROOT}/test/test/-/7297abc/${localFile.path}`, - ); - - done(); - }) - .catch(done.fail); + it('calls the service', () => { + return store.dispatch('getFileData', { path: localFile.path }).then(() => { + expect(service.getFileData).toHaveBeenCalledWith( + `${RELATIVE_URL_ROOT}/test/test/-/7297abc/${localFile.path}`, + ); + }); }); - it('sets document title with the branchId', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(document.title).toBe(`${localFile.path} · master · test/test · GitLab`); - done(); - }) - .catch(done.fail); + it('sets document title with the branchId', () => { + return store.dispatch('getFileData', { path: localFile.path }).then(() => { + expect(document.title).toBe(`${localFile.path} · master · test/test · GitLab`); + }); }); - it('sets the file as active', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(localFile.active).toBeTruthy(); - - done(); - }) - .catch(done.fail); + it('sets the file as active', () => { + return store.dispatch('getFileData', { path: localFile.path }).then(() => { + expect(localFile.active).toBeTruthy(); + }); }); - it('sets the file not as active if we pass makeFileActive false', done => { - store + it('sets the file not as active if we pass makeFileActive false', () => { + return store .dispatch('getFileData', { path: localFile.path, makeFileActive: false }) .then(() => { expect(localFile.active).toBeFalsy(); - - done(); - }) - .catch(done.fail); + }); }); - it('adds the file to open files', done => { - store - .dispatch('getFileData', { path: localFile.path }) + it('does not update the page title with the path of the file if makeFileActive is false', () => { + document.title = 'dummy title'; + return store + .dispatch('getFileData', { path: localFile.path, makeFileActive: false }) .then(() => { - expect(store.state.openFiles.length).toBe(1); - expect(store.state.openFiles[0].name).toBe(localFile.name); + expect(document.title).toBe(`dummy title`); + }); + }); - done(); - }) - .catch(done.fail); + it('adds the file to open files', () => { + return store.dispatch('getFileData', { path: localFile.path }).then(() => { + expect(store.state.openFiles.length).toBe(1); + expect(store.state.openFiles[0].name).toBe(localFile.name); + }); }); }); @@ -342,15 +313,10 @@ describe('IDE store file actions', () => { ); }); - it('sets document title considering `prevPath` on a file', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(document.title).toBe(`new-shiny-file · master · test/test · GitLab`); - - done(); - }) - .catch(done.fail); + it('sets document title considering `prevPath` on a file', () => { + return store.dispatch('getFileData', { path: localFile.path }).then(() => { + expect(document.title).toBe(`new-shiny-file · master · test/test · GitLab`); + }); }); }); @@ -397,29 +363,19 @@ describe('IDE store file actions', () => { mock.onGet(/(.*)/).replyOnce(200, 'raw'); }); - it('calls getRawFileData service method', done => { - store - .dispatch('getRawFileData', { path: tmpFile.path }) - .then(() => { - expect(service.getRawFileData).toHaveBeenCalledWith(tmpFile); - - done(); - }) - .catch(done.fail); + it('calls getRawFileData service method', () => { + return store.dispatch('getRawFileData', { path: tmpFile.path }).then(() => { + expect(service.getRawFileData).toHaveBeenCalledWith(tmpFile); + }); }); - it('updates file raw data', done => { - store - .dispatch('getRawFileData', { path: tmpFile.path }) - .then(() => { - expect(tmpFile.raw).toBe('raw'); - - done(); - }) - .catch(done.fail); + it('updates file raw data', () => { + return store.dispatch('getRawFileData', { path: tmpFile.path }).then(() => { + expect(tmpFile.raw).toBe('raw'); + }); }); - it('calls also getBaseRawFileData service method', done => { + it('calls also getBaseRawFileData service method', () => { jest.spyOn(service, 'getBaseRawFileData').mockReturnValue(Promise.resolve('baseraw')); store.state.currentProjectId = 'gitlab-org/gitlab-ce'; @@ -436,15 +392,58 @@ describe('IDE store file actions', () => { tmpFile.mrChange = { new_file: false }; - store - .dispatch('getRawFileData', { path: tmpFile.path }) - .then(() => { - expect(service.getBaseRawFileData).toHaveBeenCalledWith(tmpFile, 'SHA'); - expect(tmpFile.baseRaw).toBe('baseraw'); + return store.dispatch('getRawFileData', { path: tmpFile.path }).then(() => { + expect(service.getBaseRawFileData).toHaveBeenCalledWith(tmpFile, 'SHA'); + expect(tmpFile.baseRaw).toBe('baseraw'); + }); + }); + + describe('sets file loading to true', () => { + let loadingWhenGettingRawData; + let loadingWhenGettingBaseRawData; + + beforeEach(() => { + loadingWhenGettingRawData = undefined; + loadingWhenGettingBaseRawData = undefined; + + jest.spyOn(service, 'getRawFileData').mockImplementation(f => { + loadingWhenGettingRawData = f.loading; + return Promise.resolve('raw'); + }); + jest.spyOn(service, 'getBaseRawFileData').mockImplementation(f => { + loadingWhenGettingBaseRawData = f.loading; + return Promise.resolve('rawBase'); + }); + }); - done(); - }) - .catch(done.fail); + it('when getting raw file data', async () => { + expect(tmpFile.loading).toBe(false); + + await store.dispatch('getRawFileData', { path: tmpFile.path }); + + expect(loadingWhenGettingRawData).toBe(true); + expect(tmpFile.loading).toBe(false); + }); + + it('when getting base raw file data', async () => { + tmpFile.mrChange = { new_file: false }; + + expect(tmpFile.loading).toBe(false); + + await store.dispatch('getRawFileData', { path: tmpFile.path }); + + expect(loadingWhenGettingBaseRawData).toBe(true); + expect(tmpFile.loading).toBe(false); + }); + + it('when file was already loading', async () => { + tmpFile.loading = true; + + await store.dispatch('getRawFileData', { path: tmpFile.path }); + + expect(loadingWhenGettingRawData).toBe(true); + expect(tmpFile.loading).toBe(false); + }); }); }); @@ -453,15 +452,10 @@ describe('IDE store file actions', () => { mock.onGet(/(.*)/).replyOnce(200, JSON.stringify({ test: '123' })); }); - it('does not parse returned JSON', done => { - store - .dispatch('getRawFileData', { path: tmpFile.path }) - .then(() => { - expect(tmpFile.raw).toEqual('{"test":"123"}'); - - done(); - }) - .catch(done.fail); + it('does not parse returned JSON', () => { + return store.dispatch('getRawFileData', { path: tmpFile.path }).then(() => { + expect(tmpFile.raw).toEqual('{"test":"123"}'); + }); }); }); @@ -489,6 +483,12 @@ describe('IDE store file actions', () => { }); }); }); + + it('toggles loading off after error', async () => { + await expect(store.dispatch('getRawFileData', { path: tmpFile.path })).rejects.toThrow(); + + expect(tmpFile.loading).toBe(false); + }); }); }); @@ -504,32 +504,25 @@ describe('IDE store file actions', () => { store.state.entries[tmpFile.path] = tmpFile; }); - it('updates file content', done => { - callAction() - .then(() => { - expect(tmpFile.content).toBe('content\n'); - - done(); - }) - .catch(done.fail); + it('updates file content', () => { + return callAction().then(() => { + expect(tmpFile.content).toBe('content\n'); + }); }); - it('adds file into stagedFiles array', done => { - store + it('adds file into stagedFiles array', () => { + return store .dispatch('changeFileContent', { path: tmpFile.path, content: 'content', }) .then(() => { expect(store.state.stagedFiles.length).toBe(1); - - done(); - }) - .catch(done.fail); + }); }); - it('adds file not more than once into stagedFiles array', done => { - store + it('adds file not more than once into stagedFiles array', () => { + return store .dispatch('changeFileContent', { path: tmpFile.path, content: 'content', @@ -542,14 +535,11 @@ describe('IDE store file actions', () => { ) .then(() => { expect(store.state.stagedFiles.length).toBe(1); - - done(); - }) - .catch(done.fail); + }); }); - it('removes file from changedFiles array if not changed', done => { - store + it('removes file from changedFiles array if not changed', () => { + return store .dispatch('changeFileContent', { path: tmpFile.path, content: 'content\n', @@ -562,10 +552,7 @@ describe('IDE store file actions', () => { ) .then(() => { expect(store.state.changedFiles.length).toBe(0); - - done(); - }) - .catch(done.fail); + }); }); }); @@ -723,52 +710,36 @@ describe('IDE store file actions', () => { store.state.entries[f.path] = f; }); - it('makes file pending in openFiles', done => { - store - .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) - .then(() => { - expect(store.state.openFiles[0].pending).toBe(true); - }) - .then(done) - .catch(done.fail); + it('makes file pending in openFiles', () => { + return store.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }).then(() => { + expect(store.state.openFiles[0].pending).toBe(true); + }); }); - it('returns true when opened', done => { - store - .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) - .then(added => { - expect(added).toBe(true); - }) - .then(done) - .catch(done.fail); + it('returns true when opened', () => { + return store.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }).then(added => { + expect(added).toBe(true); + }); }); - it('returns false when already opened', done => { + it('returns false when already opened', () => { store.state.openFiles.push({ ...f, active: true, key: `pending-${f.key}`, }); - store - .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) - .then(added => { - expect(added).toBe(false); - }) - .then(done) - .catch(done.fail); + return store.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }).then(added => { + expect(added).toBe(false); + }); }); - it('pushes router URL when added', done => { + it('pushes router URL when added', () => { store.state.currentBranchId = 'master'; - store - .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) - .then(() => { - expect(router.push).toHaveBeenCalledWith('/project/123/tree/master/'); - }) - .then(done) - .catch(done.fail); + return store.dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }).then(() => { + expect(router.push).toHaveBeenCalledWith('/project/123/tree/master/'); + }); }); }); @@ -784,26 +755,18 @@ describe('IDE store file actions', () => { }; }); - it('removes pending file from open files', done => { + it('removes pending file from open files', () => { store.state.openFiles.push(f); - store - .dispatch('removePendingTab', f) - .then(() => { - expect(store.state.openFiles.length).toBe(0); - }) - .then(done) - .catch(done.fail); + return store.dispatch('removePendingTab', f).then(() => { + expect(store.state.openFiles.length).toBe(0); + }); }); - it('emits event to dispose model', done => { - store - .dispatch('removePendingTab', f) - .then(() => { - expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.dispose.${f.key}`); - }) - .then(done) - .catch(done.fail); + it('emits event to dispose model', () => { + return store.dispatch('removePendingTab', f).then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.dispose.${f.key}`); + }); }); }); @@ -812,14 +775,10 @@ describe('IDE store file actions', () => { jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); }); - it('emits event that files have changed', done => { - store - .dispatch('triggerFilesChange') - .then(() => { - expect(eventHub.$emit).toHaveBeenCalledWith('ide.files.change'); - }) - .then(done) - .catch(done.fail); + it('emits event that files have changed', () => { + return store.dispatch('triggerFilesChange').then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('ide.files.change'); + }); }); }); }); diff --git a/spec/frontend/ide/stores/actions/merge_request_spec.js b/spec/frontend/ide/stores/actions/merge_request_spec.js index cb4eebd97d9..e5c4f346459 100644 --- a/spec/frontend/ide/stores/actions/merge_request_spec.js +++ b/spec/frontend/ide/stores/actions/merge_request_spec.js @@ -55,6 +55,7 @@ describe('IDE store merge request actions', () => { expect(service.getProjectMergeRequests).toHaveBeenCalledWith(TEST_PROJECT, { source_branch: 'bar', source_project_id: TEST_PROJECT_ID, + state: 'opened', order_by: 'created_at', per_page: 1, }); diff --git a/spec/frontend/ide/stores/actions/tree_spec.js b/spec/frontend/ide/stores/actions/tree_spec.js index 44e2fcab436..c20941843c4 100644 --- a/spec/frontend/ide/stores/actions/tree_spec.js +++ b/spec/frontend/ide/stores/actions/tree_spec.js @@ -7,6 +7,7 @@ import { createStore } from '~/ide/stores'; import service from '~/ide/services'; import { createRouter } from '~/ide/ide_router'; import { file, createEntriesFromPaths } from '../../helpers'; +import { TEST_HOST } from 'jest/helpers/test_constants'; describe('Multi-file store tree actions', () => { let projectTree; @@ -97,7 +98,7 @@ describe('Multi-file store tree actions', () => { store.state.projects = { 'abc/def': { - web_url: `${gl.TEST_HOST}/files`, + web_url: `${TEST_HOST}/files`, branches: { 'master-testing': { commit: { diff --git a/spec/frontend/ide/utils_spec.js b/spec/frontend/ide/utils_spec.js index 15baeca7f36..b6de576a0a4 100644 --- a/spec/frontend/ide/utils_spec.js +++ b/spec/frontend/ide/utils_spec.js @@ -1,6 +1,7 @@ import { isTextFile, registerLanguages, + registerSchemas, trimPathComponents, insertFinalNewline, trimTrailingWhitespace, @@ -158,6 +159,57 @@ describe('WebIDE utils', () => { }); }); + describe('registerSchemas', () => { + let options; + + beforeEach(() => { + options = { + validate: true, + enableSchemaRequest: true, + hover: true, + completion: true, + schemas: [ + { + uri: 'http://myserver/foo-schema.json', + fileMatch: ['*'], + schema: { + id: 'http://myserver/foo-schema.json', + type: 'object', + properties: { + p1: { enum: ['v1', 'v2'] }, + p2: { $ref: 'http://myserver/bar-schema.json' }, + }, + }, + }, + { + uri: 'http://myserver/bar-schema.json', + schema: { + id: 'http://myserver/bar-schema.json', + type: 'object', + properties: { q1: { enum: ['x1', 'x2'] } }, + }, + }, + ], + }; + + jest.spyOn(languages.json.jsonDefaults, 'setDiagnosticsOptions'); + jest.spyOn(languages.yaml.yamlDefaults, 'setDiagnosticsOptions'); + }); + + it.each` + language | defaultsObj + ${'json'} | ${languages.json.jsonDefaults} + ${'yaml'} | ${languages.yaml.yamlDefaults} + `( + 'registers the given schemas with monaco for lang: $language', + ({ language, defaultsObj }) => { + registerSchemas({ language, options }); + + expect(defaultsObj.setDiagnosticsOptions).toHaveBeenCalledWith(options); + }, + ); + }); + describe('trimTrailingWhitespace', () => { it.each` input | output |