diff options
Diffstat (limited to 'spec/frontend/ide/components/preview/clientside_spec.js')
-rw-r--r-- | spec/frontend/ide/components/preview/clientside_spec.js | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/spec/frontend/ide/components/preview/clientside_spec.js b/spec/frontend/ide/components/preview/clientside_spec.js new file mode 100644 index 00000000000..dfc76628d0c --- /dev/null +++ b/spec/frontend/ide/components/preview/clientside_spec.js @@ -0,0 +1,318 @@ +import Vuex from 'vuex'; +import { GlLoadingIcon } from '@gitlab/ui'; +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import smooshpack from 'smooshpack'; +import Clientside from '~/ide/components/preview/clientside.vue'; + +jest.mock('smooshpack', () => ({ + Manager: jest.fn(), +})); + +const localVue = createLocalVue(); +localVue.use(Vuex); + +const dummyPackageJson = () => ({ + raw: JSON.stringify({ + main: 'index.js', + }), +}); + +describe('IDE clientside preview', () => { + let wrapper; + let store; + const storeActions = { + getFileData: jest.fn().mockReturnValue(Promise.resolve({})), + getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')), + }; + + const waitForCalls = () => new Promise(setImmediate); + + const createComponent = ({ state, getters } = {}) => { + store = new Vuex.Store({ + state: { + entries: {}, + links: {}, + ...state, + }, + getters: { + packageJson: () => '', + currentProject: () => ({ + visibility: 'public', + }), + ...getters, + }, + actions: storeActions, + }); + + wrapper = shallowMount(Clientside, { + sync: false, + store, + localVue, + }); + }; + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('without main entry', () => { + it('creates sandpack manager', () => { + createComponent(); + expect(smooshpack.Manager).not.toHaveBeenCalled(); + }); + }); + describe('with main entry', () => { + beforeEach(() => { + createComponent({ getters: { packageJson: dummyPackageJson } }); + return wrapper.vm.initPreview(); + }); + + it('creates sandpack manager', () => { + expect(smooshpack.Manager).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 } }); + wrapper.setData({ loading: true }); + + expect(wrapper.vm.showPreview).toBe(false); + }); + + it('returns true if not loading and mainEntry exists', () => { + createComponent({ getters: { packageJson: dummyPackageJson } }); + wrapper.setData({ loading: false }); + + expect(wrapper.vm.showPreview).toBe(true); + }); + }); + + describe('showEmptyState', () => { + it('returns true if no mainEntry exists', () => { + createComponent(); + wrapper.setData({ loading: false }); + expect(wrapper.vm.showEmptyState).toBe(true); + }); + + it('returns false if loading', () => { + createComponent(); + wrapper.setData({ loading: true }); + + expect(wrapper.vm.showEmptyState).toBe(false); + }); + + it('returns false if not loading and mainEntry exists', () => { + createComponent({ getters: { packageJson: dummyPackageJson } }); + wrapper.setData({ loading: false }); + + expect(wrapper.vm.showEmptyState).toBe(false); + }); + }); + + describe('showOpenInCodeSandbox', () => { + it('returns true when visiblity is public', () => { + createComponent({ getters: { currentProject: () => ({ visibility: 'public' }) } }); + + expect(wrapper.vm.showOpenInCodeSandbox).toBe(true); + }); + + it('returns false when visiblity 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, + }, + undefined, // vuex callback + ); + }); + + it('calls getRawFileData', () => { + expect(storeActions.getRawFileData).toHaveBeenCalledWith( + expect.any(Object), + { + path: 'package.json', + }, + undefined, // vuex callback + ); + }); + }); + + describe('update', () => { + beforeEach(() => { + createComponent(); + wrapper.setData({ sandpackReady: true }); + }); + + it('initializes manager if manager is empty', () => { + createComponent({ getters: { packageJson: dummyPackageJson } }); + wrapper.setData({ sandpackReady: true }); + wrapper.vm.update(); + + jest.advanceTimersByTime(250); + + return waitForCalls().then(() => { + expect(smooshpack.Manager).toHaveBeenCalled(); + }); + }); + + it('calls updatePreview', () => { + wrapper.setData({ + manager: { + listener: jest.fn(), + updatePreview: jest.fn(), + }, + }); + wrapper.vm.update(); + + jest.advanceTimersByTime(250); + expect(wrapper.vm.manager.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts); + }); + }); + }); + + describe('template', () => { + it('renders ide-preview element when showPreview is true', () => { + createComponent({ getters: { packageJson: dummyPackageJson } }); + wrapper.setData({ loading: false }); + + return wrapper.vm.$nextTick(() => { + expect(wrapper.find('#ide-preview').exists()).toBe(true); + }); + }); + + it('renders empty state', () => { + createComponent(); + wrapper.setData({ loading: false }); + + return wrapper.vm.$nextTick(() => { + expect(wrapper.text()).toContain( + 'Preview your web application using Web IDE client-side evaluation.', + ); + }); + }); + + it('renders loading icon', () => { + createComponent(); + wrapper.setData({ loading: true }); + + return wrapper.vm.$nextTick(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + }); + }); + }); +}); |