diff options
Diffstat (limited to 'spec/frontend/ide/components')
-rw-r--r-- | spec/frontend/ide/components/panes/right_spec.js | 25 | ||||
-rw-r--r-- | spec/frontend/ide/components/preview/clientside_spec.js | 416 | ||||
-rw-r--r-- | spec/frontend/ide/components/preview/navigator_spec.js | 161 | ||||
-rw-r--r-- | spec/frontend/ide/components/repo_editor_spec.js | 3 |
4 files changed, 2 insertions, 603 deletions
diff --git a/spec/frontend/ide/components/panes/right_spec.js b/spec/frontend/ide/components/panes/right_spec.js index 294f5eee863..1d81c3ea89d 100644 --- a/spec/frontend/ide/components/panes/right_spec.js +++ b/spec/frontend/ide/components/panes/right_spec.js @@ -68,31 +68,6 @@ describe('ide/components/panes/right.vue', () => { }); }); - describe('clientside live preview tab', () => { - it('is shown if there is a packageJson and clientsidePreviewEnabled', () => { - Vue.set(store.state.entries, 'package.json', { - name: 'package.json', - }); - store.state.clientsidePreviewEnabled = true; - - createComponent(); - - expect(wrapper.findComponent(CollapsibleSidebar).props('extensionTabs')).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - show: true, - title: 'Live preview', - views: expect.arrayContaining([ - expect.objectContaining({ - name: rightSidebarViews.clientSidePreview.name, - }), - ]), - }), - ]), - ); - }); - }); - describe('terminal tab', () => { beforeEach(() => { createComponent(); diff --git a/spec/frontend/ide/components/preview/clientside_spec.js b/spec/frontend/ide/components/preview/clientside_spec.js deleted file mode 100644 index 51e6a9d9034..00000000000 --- a/spec/frontend/ide/components/preview/clientside_spec.js +++ /dev/null @@ -1,416 +0,0 @@ -import { GlLoadingIcon } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import Vue, { nextTick } from 'vue'; -import { dispatch } from 'codesandbox-api'; -import { SandpackClient } from '@codesandbox/sandpack-client'; -import Vuex from 'vuex'; -import waitForPromises from 'helpers/wait_for_promises'; -import Clientside from '~/ide/components/preview/clientside.vue'; -import { PING_USAGE_PREVIEW_KEY, PING_USAGE_PREVIEW_SUCCESS_KEY } from '~/ide/constants'; -import eventHub from '~/ide/eventhub'; - -jest.mock('@codesandbox/sandpack-client', () => ({ - SandpackClient: jest.fn(), -})); - -Vue.use(Vuex); - -const dummyPackageJson = () => ({ - raw: JSON.stringify({ - main: 'index.js', - }), -}); -const expectedSandpackOptions = () => ({ - files: {}, - entry: '/index.js', - showOpenInCodeSandbox: true, -}); -const expectedSandpackSettings = () => ({ - fileResolver: { - isFile: expect.any(Function), - readFile: expect.any(Function), - }, -}); - -describe('IDE clientside preview', () => { - let wrapper; - let store; - const storeActions = { - getFileData: jest.fn().mockReturnValue(Promise.resolve({})), - getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')), - }; - const storeClientsideActions = { - pingUsage: jest.fn().mockReturnValue(Promise.resolve({})), - }; - const dispatchCodesandboxReady = () => dispatch({ type: 'done' }); - - const createComponent = ({ state, getters } = {}) => { - store = new Vuex.Store({ - state: { - entries: {}, - links: {}, - ...state, - }, - getters: { - packageJson: () => '', - currentProject: () => ({ - visibility: 'public', - }), - ...getters, - }, - actions: storeActions, - modules: { - clientside: { - namespaced: true, - actions: storeClientsideActions, - }, - }, - }); - - wrapper = shallowMount(Clientside, { - store, - }); - }; - - const createInitializedComponent = () => { - createComponent(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - sandpackReady: true, - client: { - cleanup: jest.fn(), - updatePreview: jest.fn(), - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe('without main entry', () => { - it('creates sandpack client', () => { - createComponent(); - expect(SandpackClient).not.toHaveBeenCalled(); - }); - }); - describe('with main entry', () => { - beforeEach(() => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - - return waitForPromises(); - }); - - it('creates sandpack client', () => { - expect(SandpackClient).toHaveBeenCalledWith( - '#ide-preview', - expectedSandpackOptions(), - expectedSandpackSettings(), - ); - }); - - it('pings usage', () => { - expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1); - expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith( - expect.anything(), - PING_USAGE_PREVIEW_KEY, - ); - }); - - it('pings usage success', async () => { - dispatchCodesandboxReady(); - await nextTick(); - expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(2); - expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith( - expect.anything(), - PING_USAGE_PREVIEW_SUCCESS_KEY, - ); - }); - }); - - describe('with codesandboxBundlerUrl', () => { - const TEST_BUNDLER_URL = 'https://test.gitlab-static.test'; - - beforeEach(() => { - createComponent({ - getters: { packageJson: dummyPackageJson }, - state: { codesandboxBundlerUrl: TEST_BUNDLER_URL }, - }); - - return waitForPromises(); - }); - - it('creates sandpack client with bundlerURL', () => { - expect(SandpackClient).toHaveBeenCalledWith('#ide-preview', expectedSandpackOptions(), { - ...expectedSandpackSettings(), - bundlerURL: TEST_BUNDLER_URL, - }); - }); - }); - - describe('with codesandboxBundlerURL', () => { - beforeEach(() => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - - return waitForPromises(); - }); - - it('creates sandpack client', () => { - expect(SandpackClient).toHaveBeenCalledWith( - '#ide-preview', - { - files: {}, - entry: '/index.js', - showOpenInCodeSandbox: true, - }, - { - fileResolver: { - isFile: expect.any(Function), - readFile: expect.any(Function), - }, - }, - ); - }); - }); - - describe('computed', () => { - describe('normalizedEntries', () => { - it('returns flattened list of blobs with content', () => { - createComponent({ - state: { - entries: { - 'index.js': { type: 'blob', raw: 'test' }, - 'index2.js': { type: 'blob', content: 'content' }, - tree: { type: 'tree' }, - empty: { type: 'blob' }, - }, - }, - }); - - expect(wrapper.vm.normalizedEntries).toEqual({ - '/index.js': { - code: 'test', - }, - '/index2.js': { - code: 'content', - }, - }); - }); - }); - - describe('mainEntry', () => { - it('returns false when package.json is empty', () => { - createComponent(); - expect(wrapper.vm.mainEntry).toBe(false); - }); - - it('returns main key from package.json', () => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - expect(wrapper.vm.mainEntry).toBe('index.js'); - }); - }); - - describe('showPreview', () => { - it('returns false if no mainEntry', () => { - createComponent(); - expect(wrapper.vm.showPreview).toBe(false); - }); - - it('returns false if loading and mainEntry exists', () => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: true }); - - expect(wrapper.vm.showPreview).toBe(false); - }); - - it('returns true if not loading and mainEntry exists', () => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: false }); - - expect(wrapper.vm.showPreview).toBe(true); - }); - }); - - describe('showEmptyState', () => { - it('returns true if no mainEntry exists', () => { - createComponent(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: false }); - expect(wrapper.vm.showEmptyState).toBe(true); - }); - - it('returns false if loading', () => { - createComponent(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: true }); - - expect(wrapper.vm.showEmptyState).toBe(false); - }); - - it('returns false if not loading and mainEntry exists', () => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: false }); - - expect(wrapper.vm.showEmptyState).toBe(false); - }); - }); - - describe('showOpenInCodeSandbox', () => { - it('returns true when visibility is public', () => { - createComponent({ getters: { currentProject: () => ({ visibility: 'public' }) } }); - - expect(wrapper.vm.showOpenInCodeSandbox).toBe(true); - }); - - it('returns false when visibility is private', () => { - createComponent({ getters: { currentProject: () => ({ visibility: 'private' }) } }); - - expect(wrapper.vm.showOpenInCodeSandbox).toBe(false); - }); - }); - - describe('sandboxOpts', () => { - beforeEach(() => { - createComponent({ - state: { - entries: { - 'index.js': { type: 'blob', raw: 'test' }, - 'package.json': dummyPackageJson(), - }, - }, - getters: { - packageJson: dummyPackageJson, - }, - }); - }); - - it('returns sandbox options', () => { - expect(wrapper.vm.sandboxOpts).toEqual({ - files: { - '/index.js': { - code: 'test', - }, - '/package.json': { - code: '{"main":"index.js"}', - }, - }, - entry: '/index.js', - showOpenInCodeSandbox: true, - }); - }); - }); - }); - - describe('methods', () => { - describe('loadFileContent', () => { - beforeEach(() => { - createComponent(); - return wrapper.vm.loadFileContent('package.json'); - }); - - it('calls getFileData', () => { - expect(storeActions.getFileData).toHaveBeenCalledWith(expect.any(Object), { - path: 'package.json', - makeFileActive: false, - }); - }); - - it('calls getRawFileData', () => { - expect(storeActions.getRawFileData).toHaveBeenCalledWith(expect.any(Object), { - path: 'package.json', - }); - }); - }); - - describe('update', () => { - it('initializes client if client is empty', () => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ sandpackReady: true }); - wrapper.vm.update(); - - return waitForPromises().then(() => { - expect(SandpackClient).toHaveBeenCalled(); - }); - }); - - it('calls updatePreview', () => { - createInitializedComponent(); - - wrapper.vm.update(); - - expect(wrapper.vm.client.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts); - }); - }); - - describe('on ide.files.change event', () => { - beforeEach(() => { - createInitializedComponent(); - - eventHub.$emit('ide.files.change'); - }); - - it('calls updatePreview', () => { - expect(wrapper.vm.client.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts); - }); - }); - }); - - describe('template', () => { - it('renders ide-preview element when showPreview is true', async () => { - createComponent({ getters: { packageJson: dummyPackageJson } }); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: false }); - - await nextTick(); - expect(wrapper.find('#ide-preview').exists()).toBe(true); - }); - - it('renders empty state', async () => { - createComponent(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: false }); - - await nextTick(); - expect(wrapper.text()).toContain( - 'Preview your web application using Web IDE client-side evaluation.', - ); - }); - - it('renders loading icon', async () => { - createComponent(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ loading: true }); - - await nextTick(); - expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); - }); - }); - - describe('when destroyed', () => { - let spy; - - beforeEach(() => { - createInitializedComponent(); - spy = wrapper.vm.client.updatePreview; - wrapper.destroy(); - }); - - it('does not call updatePreview', () => { - expect(spy).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/frontend/ide/components/preview/navigator_spec.js b/spec/frontend/ide/components/preview/navigator_spec.js deleted file mode 100644 index 043dcade858..00000000000 --- a/spec/frontend/ide/components/preview/navigator_spec.js +++ /dev/null @@ -1,161 +0,0 @@ -import { GlLoadingIcon } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import { listen } from 'codesandbox-api'; -import { nextTick } from 'vue'; -import { TEST_HOST } from 'helpers/test_constants'; -import ClientsideNavigator from '~/ide/components/preview/navigator.vue'; - -jest.mock('codesandbox-api', () => ({ - listen: jest.fn().mockReturnValue(jest.fn()), -})); - -describe('IDE clientside preview navigator', () => { - let wrapper; - let client; - let listenHandler; - - const findBackButton = () => wrapper.findAll('button').at(0); - const findForwardButton = () => wrapper.findAll('button').at(1); - const findRefreshButton = () => wrapper.findAll('button').at(2); - - beforeEach(() => { - listen.mockClear(); - client = { bundlerURL: TEST_HOST, iframe: { src: '' } }; - - wrapper = shallowMount(ClientsideNavigator, { propsData: { client } }); - [[listenHandler]] = listen.mock.calls; - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders readonly URL bar', async () => { - listenHandler({ type: 'urlchange', url: client.bundlerURL }); - await nextTick(); - expect(wrapper.find('input[readonly]').element.value).toBe('/'); - }); - - it('renders loading icon by default', () => { - expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); - }); - - it('removes loading icon when done event is fired', async () => { - listenHandler({ type: 'done' }); - await nextTick(); - expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false); - }); - - it('does not count visiting same url multiple times', async () => { - listenHandler({ type: 'done' }); - listenHandler({ type: 'done', url: `${TEST_HOST}/url1` }); - listenHandler({ type: 'done', url: `${TEST_HOST}/url1` }); - await nextTick(); - expect(findBackButton().attributes('disabled')).toBe('disabled'); - }); - - it('unsubscribes from listen on destroy', () => { - const unsubscribeFn = listen(); - - wrapper.destroy(); - expect(unsubscribeFn).toHaveBeenCalled(); - }); - - describe('back button', () => { - beforeEach(async () => { - listenHandler({ type: 'done' }); - listenHandler({ type: 'urlchange', url: TEST_HOST }); - await nextTick(); - }); - - it('is disabled by default', () => { - expect(findBackButton().attributes('disabled')).toBe('disabled'); - }); - - it('is enabled when there is previous entry', async () => { - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` }); - await nextTick(); - findBackButton().trigger('click'); - expect(findBackButton().attributes()).not.toHaveProperty('disabled'); - }); - - it('is disabled when there is no previous entry', async () => { - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` }); - - await nextTick(); - findBackButton().trigger('click'); - - await nextTick(); - expect(findBackButton().attributes('disabled')).toBe('disabled'); - }); - - it('updates client iframe src', async () => { - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` }); - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` }); - await nextTick(); - findBackButton().trigger('click'); - - expect(client.iframe.src).toBe(`${TEST_HOST}/url1`); - }); - }); - - describe('forward button', () => { - beforeEach(async () => { - listenHandler({ type: 'done' }); - listenHandler({ type: 'urlchange', url: TEST_HOST }); - await nextTick(); - }); - - it('is disabled by default', () => { - expect(findForwardButton().attributes('disabled')).toBe('disabled'); - }); - - it('is enabled when there is next entry', async () => { - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` }); - - await nextTick(); - findBackButton().trigger('click'); - - await nextTick(); - expect(findForwardButton().attributes()).not.toHaveProperty('disabled'); - }); - - it('is disabled when there is no next entry', async () => { - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` }); - - await nextTick(); - findBackButton().trigger('click'); - - await nextTick(); - findForwardButton().trigger('click'); - - await nextTick(); - expect(findForwardButton().attributes('disabled')).toBe('disabled'); - }); - - it('updates client iframe src', async () => { - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` }); - listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` }); - await nextTick(); - findBackButton().trigger('click'); - - expect(client.iframe.src).toBe(`${TEST_HOST}/url1`); - }); - }); - - describe('refresh button', () => { - const url = `${TEST_HOST}/some_url`; - beforeEach(async () => { - listenHandler({ type: 'done' }); - listenHandler({ type: 'urlchange', url }); - await nextTick(); - }); - - it('calls refresh with current path', () => { - client.iframe.src = 'something-other'; - findRefreshButton().trigger('click'); - - expect(client.iframe.src).toBe(url); - }); - }); -}); diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js index 9092d73571b..c9f033bffbb 100644 --- a/spec/frontend/ide/components/repo_editor_spec.js +++ b/spec/frontend/ide/components/repo_editor_spec.js @@ -22,6 +22,7 @@ import ModelManager from '~/ide/lib/common/model_manager'; import service from '~/ide/services'; import { createStoreOptions } from '~/ide/stores'; import axios from '~/lib/utils/axios_utils'; +import { HTTP_STATUS_OK } from '~/lib/utils/http_status'; import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; import SourceEditorInstance from '~/editor/source_editor_instance'; import { file } from '../helpers'; @@ -265,7 +266,7 @@ describe('RepoEditor', () => { mock = new MockAdapter(axios); - mock.onPost(/(.*)\/preview_markdown/).reply(200, { + mock.onPost(/(.*)\/preview_markdown/).reply(HTTP_STATUS_OK, { body: `<p>${dummyFile.text.content}</p>`, }); }); |