From b435bbc596fa43d366177a2b64ddca5621ffbc81 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Thu, 5 Sep 2019 12:44:17 +0000 Subject: [PATCH] Refactored spec to Jest for clientside_spec --- .../ide/components/preview/clientside_spec.js | 318 +++++++++++++++ .../ide/components/preview/clientside_spec.js | 363 ------------------ 2 files changed, 318 insertions(+), 363 deletions(-) create mode 100644 spec/frontend/ide/components/preview/clientside_spec.js delete mode 100644 spec/javascripts/ide/components/preview/clientside_spec.js 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); + }); + }); + }); +}); diff --git a/spec/javascripts/ide/components/preview/clientside_spec.js b/spec/javascripts/ide/components/preview/clientside_spec.js deleted file mode 100644 index b9bf5c51ffe..00000000000 --- a/spec/javascripts/ide/components/preview/clientside_spec.js +++ /dev/null @@ -1,363 +0,0 @@ -import Vue from 'vue'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import { createStore } from '~/ide/stores'; -import Clientside from '~/ide/components/preview/clientside.vue'; -import timeoutPromise from 'spec/helpers/set_timeout_promise_helper'; -import { resetStore, file } from '../../helpers'; - -describe('IDE clientside preview', () => { - let vm; - let Component; - - beforeAll(() => { - Component = Vue.extend(Clientside); - }); - - beforeEach(done => { - const store = createStore(); - - Vue.set(store.state.entries, 'package.json', { - ...file('package.json'), - }); - Vue.set(store.state, 'currentProjectId', 'gitlab-ce'); - Vue.set(store.state.projects, 'gitlab-ce', { - visibility: 'public', - }); - - vm = createComponentWithStore(Component, store); - - spyOn(vm, 'getFileData').and.returnValue(Promise.resolve()); - spyOn(vm, 'getRawFileData').and.returnValue(Promise.resolve('')); - spyOn(vm, 'initManager'); - - vm.$mount(); - - timeoutPromise() - .then(() => vm.$nextTick()) - .then(done) - .catch(done.fail); - }); - - afterEach(() => { - vm.$destroy(); - resetStore(vm.$store); - }); - - describe('without main entry', () => { - it('creates sandpack manager', () => { - expect(vm.initManager).not.toHaveBeenCalled(); - }); - }); - - describe('with main entry', () => { - beforeEach(done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - - vm.$nextTick() - .then(() => vm.initPreview()) - .then(vm.$nextTick) - .then(done) - .catch(done.fail); - }); - - it('creates sandpack manager', () => { - expect(vm.initManager).toHaveBeenCalledWith( - '#ide-preview', - { - files: jasmine.any(Object), - entry: '/index.js', - showOpenInCodeSandbox: true, - }, - { - fileResolver: { - isFile: jasmine.any(Function), - readFile: jasmine.any(Function), - }, - }, - ); - }); - }); - - describe('computed', () => { - describe('normalizedEntries', () => { - beforeEach(done => { - vm.$store.state.entries['index.js'] = { - ...file('index.js'), - type: 'blob', - raw: 'test', - }; - vm.$store.state.entries['index2.js'] = { - ...file('index2.js'), - type: 'blob', - content: 'content', - }; - vm.$store.state.entries.tree = { - ...file('tree'), - type: 'tree', - }; - vm.$store.state.entries.empty = { - ...file('empty'), - type: 'blob', - }; - - vm.$nextTick(done); - }); - - it('returns flattened list of blobs with content', () => { - expect(vm.normalizedEntries).toEqual({ - '/index.js': { - code: 'test', - }, - '/index2.js': { - code: 'content', - }, - }); - }); - }); - - describe('mainEntry', () => { - it('returns false when package.json is empty', () => { - expect(vm.mainEntry).toBe(false); - }); - - it('returns main key from package.json', done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - - vm.$nextTick(() => { - expect(vm.mainEntry).toBe('index.js'); - - done(); - }); - }); - }); - - describe('showPreview', () => { - it('returns false if no mainEntry', () => { - expect(vm.showPreview).toBe(false); - }); - - it('returns false if loading', done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - vm.loading = true; - - vm.$nextTick(() => { - expect(vm.showPreview).toBe(false); - - done(); - }); - }); - - it('returns true if not loading and mainEntry exists', done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - vm.loading = false; - - vm.$nextTick(() => { - expect(vm.showPreview).toBe(true); - - done(); - }); - }); - }); - - describe('showEmptyState', () => { - it('returns true if no mainEnry exists', () => { - expect(vm.showEmptyState).toBe(true); - }); - - it('returns false if loading', done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - vm.loading = true; - - vm.$nextTick(() => { - expect(vm.showEmptyState).toBe(false); - - done(); - }); - }); - - it('returns false if not loading and mainEntry exists', done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - vm.loading = false; - - vm.$nextTick(() => { - expect(vm.showEmptyState).toBe(false); - - done(); - }); - }); - }); - - describe('showOpenInCodeSandbox', () => { - it('returns true when visiblity is public', () => { - expect(vm.showOpenInCodeSandbox).toBe(true); - }); - - it('returns false when visiblity is private', done => { - vm.$store.state.projects['gitlab-ce'].visibility = 'private'; - - vm.$nextTick(() => { - expect(vm.showOpenInCodeSandbox).toBe(false); - - done(); - }); - }); - }); - - describe('sandboxOpts', () => { - beforeEach(done => { - vm.$store.state.entries['index.js'] = { - ...file('index.js'), - type: 'blob', - raw: 'test', - }; - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - - vm.$nextTick(done); - }); - - it('returns sandbox options', () => { - expect(vm.sandboxOpts).toEqual({ - files: { - '/index.js': { - code: 'test', - }, - '/package.json': { - code: '{"main":"index.js"}', - }, - }, - entry: '/index.js', - showOpenInCodeSandbox: true, - }); - }); - }); - }); - - describe('methods', () => { - describe('loadFileContent', () => { - it('calls getFileData', () => { - expect(vm.getFileData).toHaveBeenCalledWith({ - path: 'package.json', - makeFileActive: false, - }); - }); - - it('calls getRawFileData', () => { - expect(vm.getRawFileData).toHaveBeenCalledWith({ path: 'package.json' }); - }); - }); - - describe('update', () => { - beforeEach(() => { - jasmine.clock().install(); - - vm.sandpackReady = true; - vm.manager.updatePreview = jasmine.createSpy('updatePreview'); - vm.manager.listener = jasmine.createSpy('updatePreview'); - }); - - afterEach(() => { - jasmine.clock().uninstall(); - }); - - it('calls initPreview if manager is empty', () => { - spyOn(vm, 'initPreview'); - vm.manager = {}; - - vm.update(); - - jasmine.clock().tick(250); - - expect(vm.initPreview).toHaveBeenCalled(); - }); - - it('calls updatePreview', () => { - vm.update(); - - jasmine.clock().tick(250); - - expect(vm.manager.updatePreview).toHaveBeenCalledWith(vm.sandboxOpts); - }); - }); - }); - - describe('template', () => { - it('renders ide-preview element when showPreview is true', done => { - Vue.set( - vm.$store.state.entries['package.json'], - 'raw', - JSON.stringify({ - main: 'index.js', - }), - ); - vm.loading = false; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('#ide-preview')).not.toBe(null); - done(); - }); - }); - - it('renders empty state', done => { - vm.loading = false; - - vm.$nextTick(() => { - expect(vm.$el.textContent).toContain( - 'Preview your web application using Web IDE client-side evaluation.', - ); - - done(); - }); - }); - - it('renders loading icon', done => { - vm.loading = true; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.loading-container')).not.toBe(null); - done(); - }); - }); - }); -});