416 lines
12 KiB
JavaScript
416 lines
12 KiB
JavaScript
import { GlLoadingIcon } from '@gitlab/ui';
|
|
import { shallowMount } from '@vue/test-utils';
|
|
import Vue, { nextTick } from 'vue';
|
|
import { dispatch } from 'codesandbox-api';
|
|
import smooshpack from 'smooshpack';
|
|
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('smooshpack', () => ({
|
|
Manager: 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,
|
|
manager: {
|
|
listener: jest.fn(),
|
|
updatePreview: jest.fn(),
|
|
},
|
|
});
|
|
};
|
|
|
|
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 waitForPromises();
|
|
});
|
|
|
|
it('creates sandpack manager', () => {
|
|
expect(smooshpack.Manager).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 manager with bundlerURL', () => {
|
|
expect(smooshpack.Manager).toHaveBeenCalledWith('#ide-preview', expectedSandpackOptions(), {
|
|
...expectedSandpackSettings(),
|
|
bundlerURL: TEST_BUNDLER_URL,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('with codesandboxBundlerURL', () => {
|
|
beforeEach(() => {
|
|
createComponent({ getters: { packageJson: dummyPackageJson } });
|
|
|
|
return waitForPromises();
|
|
});
|
|
|
|
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 } });
|
|
// 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 manager if manager 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(smooshpack.Manager).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('calls updatePreview', () => {
|
|
createInitializedComponent();
|
|
|
|
wrapper.vm.update();
|
|
|
|
expect(wrapper.vm.manager.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts);
|
|
});
|
|
});
|
|
|
|
describe('on ide.files.change event', () => {
|
|
beforeEach(() => {
|
|
createInitializedComponent();
|
|
|
|
eventHub.$emit('ide.files.change');
|
|
});
|
|
|
|
it('calls updatePreview', () => {
|
|
expect(wrapper.vm.manager.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.find(GlLoadingIcon).exists()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('when destroyed', () => {
|
|
let spy;
|
|
|
|
beforeEach(() => {
|
|
createInitializedComponent();
|
|
spy = wrapper.vm.manager.updatePreview;
|
|
wrapper.destroy();
|
|
});
|
|
|
|
it('does not call updatePreview', () => {
|
|
expect(spy).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|