From b63cce88ad5ba361b6b94382f41166609a2e152f Mon Sep 17 00:00:00 2001 From: Paul Slaughter <pslaughter@gitlab.com> Date: Fri, 20 Nov 2020 16:20:45 -0600 Subject: [PATCH] Disallow fs in FE integration specs - This is because we'd like to run these in the browser - Also removes a potential circular dependency when loading specs in the browser --- jest.config.base.js | 6 ++- spec/frontend_integration/.eslintrc.yml | 4 ++ .../ide/helpers/ide_helper.js | 17 ------ .../frontend_integration/ide/helpers/start.js | 17 ++++++ .../ide/ide_integration_spec.js | 5 +- .../ide/user_opens_ide_spec.js | 17 +++--- .../test_helpers/fixtures.js | 52 ++++++++++++------- 7 files changed, 71 insertions(+), 47 deletions(-) create mode 100644 spec/frontend_integration/ide/helpers/start.js diff --git a/jest.config.base.js b/jest.config.base.js index 9f6117757766e..40f16c6d12449 100644 --- a/jest.config.base.js +++ b/jest.config.base.js @@ -30,6 +30,8 @@ module.exports = path => { testMatch = testMatch.map(path => path.replace('_spec.js', '')); } + const TEST_FIXTURES_PATTERN = 'test_fixtures(/.*)$'; + const moduleNameMapper = { '^~(/.*)$': '<rootDir>/app/assets/javascripts$1', '^ee_component(/.*)$': @@ -38,12 +40,12 @@ module.exports = path => { '^ee_else_ce(/.*)$': '<rootDir>/app/assets/javascripts$1', '^helpers(/.*)$': '<rootDir>/spec/frontend/helpers$1', '^vendor(/.*)$': '<rootDir>/vendor/assets/javascripts$1', + [TEST_FIXTURES_PATTERN]: '<rootDir>/tmp/tests/frontend/fixtures$1', '\\.(jpg|jpeg|png|svg|css)$': '<rootDir>/spec/frontend/__mocks__/file_mock.js', 'emojis(/.*).json': '<rootDir>/fixtures/emojis$1.json', '^spec/test_constants$': '<rootDir>/spec/frontend/helpers/test_constants', '^jest/(.*)$': '<rootDir>/spec/frontend/$1', 'test_helpers(/.*)$': '<rootDir>/spec/frontend_integration/test_helpers$1', - 'test_fixtures(/.*)$': '<rootDir>/tmp/tests/frontend/fixtures$1', }; const collectCoverageFrom = ['<rootDir>/app/assets/javascripts/**/*.{js,vue}']; @@ -55,7 +57,7 @@ module.exports = path => { '^ee_component(/.*)$': rootDirEE, '^ee_else_ce(/.*)$': rootDirEE, '^ee_jest/(.*)$': '<rootDir>/ee/spec/frontend/$1', - 'test_fixtures(/.*)$': '<rootDir>/tmp/tests/frontend/fixtures-ee$1', + [TEST_FIXTURES_PATTERN]: '<rootDir>/tmp/tests/frontend/fixtures-ee$1', }); collectCoverageFrom.push(rootDirEE.replace('$1', '/**/*.{js,vue}')); diff --git a/spec/frontend_integration/.eslintrc.yml b/spec/frontend_integration/.eslintrc.yml index 2460e218f5968..8fff491bdcf85 100644 --- a/spec/frontend_integration/.eslintrc.yml +++ b/spec/frontend_integration/.eslintrc.yml @@ -4,5 +4,9 @@ settings: import/resolver: jest: jestConfigFile: 'jest.config.integration.js' +rules: + no-restricted-imports: + - error + - fs globals: mockServer: false diff --git a/spec/frontend_integration/ide/helpers/ide_helper.js b/spec/frontend_integration/ide/helpers/ide_helper.js index 7ace586fe08d2..67355025727c5 100644 --- a/spec/frontend_integration/ide/helpers/ide_helper.js +++ b/spec/frontend_integration/ide/helpers/ide_helper.js @@ -1,8 +1,4 @@ -import { TEST_HOST } from 'helpers/test_constants'; import { findAllByText, fireEvent, getByLabelText, screen } from '@testing-library/dom'; -import { initIde } from '~/ide'; -import extendStore from '~/ide/stores/extend'; -import { IDE_DATASET } from './mock_data'; const isFolderRowOpen = row => row.matches('.folder.is-open'); @@ -135,16 +131,3 @@ export const commit = async () => { screen.getByText('Commit').click(); }; - -export const createIdeComponent = (container, { isRepoEmpty = false, path = '' } = {}) => { - global.jsdom.reconfigure({ - url: `${TEST_HOST}/-/ide/project/gitlab-test/lorem-ipsum${ - isRepoEmpty ? '-empty' : '' - }/tree/master/-/${path}`, - }); - - const el = document.createElement('div'); - Object.assign(el.dataset, IDE_DATASET); - container.appendChild(el); - return initIde(el, { extendStore }); -}; diff --git a/spec/frontend_integration/ide/helpers/start.js b/spec/frontend_integration/ide/helpers/start.js new file mode 100644 index 0000000000000..9dc9649e1bfc9 --- /dev/null +++ b/spec/frontend_integration/ide/helpers/start.js @@ -0,0 +1,17 @@ +import { TEST_HOST } from 'helpers/test_constants'; +import extendStore from '~/ide/stores/extend'; +import { IDE_DATASET } from './mock_data'; +import { initIde } from '~/ide'; + +export default (container, { isRepoEmpty = false, path = '' } = {}) => { + global.jsdom.reconfigure({ + url: `${TEST_HOST}/-/ide/project/gitlab-test/lorem-ipsum${ + isRepoEmpty ? '-empty' : '' + }/tree/master/-/${path}`, + }); + + const el = document.createElement('div'); + Object.assign(el.dataset, IDE_DATASET); + container.appendChild(el); + return initIde(el, { extendStore }); +}; diff --git a/spec/frontend_integration/ide/ide_integration_spec.js b/spec/frontend_integration/ide/ide_integration_spec.js index 9d515d207493c..a17f57e221612 100644 --- a/spec/frontend_integration/ide/ide_integration_spec.js +++ b/spec/frontend_integration/ide/ide_integration_spec.js @@ -3,6 +3,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import { useOverclockTimers } from 'test_helpers/utils/overclock_timers'; import { createCommitId } from 'test_helpers/factories/commit_id'; import * as ideHelper from './helpers/ide_helper'; +import startWebIDE from './helpers/start'; describe('WebIDE', () => { useOverclockTimers(); @@ -21,7 +22,7 @@ describe('WebIDE', () => { }); it('user commits changes', async () => { - vm = ideHelper.createIdeComponent(container); + vm = startWebIDE(container); await ideHelper.createFile('foo/bar/test.txt', 'Lorem ipsum dolar sit'); await ideHelper.deleteFile('foo/bar/.gitkeep'); @@ -55,7 +56,7 @@ describe('WebIDE', () => { }); it('user adds file that starts with +', async () => { - vm = ideHelper.createIdeComponent(container); + vm = startWebIDE(container); await ideHelper.createFile('+test', 'Hello world!'); await ideHelper.openFile('+test'); diff --git a/spec/frontend_integration/ide/user_opens_ide_spec.js b/spec/frontend_integration/ide/user_opens_ide_spec.js index 958cab483eb28..645d2661b1803 100644 --- a/spec/frontend_integration/ide/user_opens_ide_spec.js +++ b/spec/frontend_integration/ide/user_opens_ide_spec.js @@ -1,6 +1,7 @@ import { useOverclockTimers } from 'test_helpers/utils/overclock_timers'; import { findByText, screen } from '@testing-library/dom'; import * as ideHelper from './helpers/ide_helper'; +import startWebIDE from './helpers/start'; describe('IDE: User opens IDE', () => { useOverclockTimers(); @@ -19,14 +20,14 @@ describe('IDE: User opens IDE', () => { }); it('shows loading indicator while the IDE is loading', async () => { - vm = ideHelper.createIdeComponent(container); + vm = startWebIDE(container); expect(container.querySelectorAll('.multi-file-loading-container')).toHaveLength(3); }); describe('when the project is empty', () => { beforeEach(() => { - vm = ideHelper.createIdeComponent(container, { isRepoEmpty: true }); + vm = startWebIDE(container, { isRepoEmpty: true }); }); it('shows "No files" in the left sidebar', async () => { @@ -42,7 +43,7 @@ describe('IDE: User opens IDE', () => { describe('when the file tree is loaded', () => { beforeEach(async () => { - vm = ideHelper.createIdeComponent(container); + vm = startWebIDE(container); await screen.findByText('README'); // wait for file tree to load }); @@ -76,7 +77,7 @@ describe('IDE: User opens IDE', () => { describe('a path to a text file is present in the URL', () => { beforeEach(async () => { - vm = ideHelper.createIdeComponent(container, { path: 'README.md' }); + vm = startWebIDE(container, { path: 'README.md' }); // a new tab is open for README.md await findByText(document.querySelector('.multi-file-edit-pane'), 'README.md'); @@ -89,7 +90,7 @@ describe('IDE: User opens IDE', () => { describe('a path to a binary file is present in the URL', () => { beforeEach(async () => { - vm = ideHelper.createIdeComponent(container, { path: 'Gemfile.zip' }); + vm = startWebIDE(container, { path: 'Gemfile.zip' }); // a new tab is open for Gemfile.zip await findByText(document.querySelector('.multi-file-edit-pane'), 'Gemfile.zip'); @@ -105,7 +106,7 @@ describe('IDE: User opens IDE', () => { describe('a path to an image is present in the URL', () => { beforeEach(async () => { - vm = ideHelper.createIdeComponent(container, { path: 'files/images/logo-white.png' }); + vm = startWebIDE(container, { path: 'files/images/logo-white.png' }); // a new tab is open for logo-white.png await findByText(document.querySelector('.multi-file-edit-pane'), 'logo-white.png'); @@ -121,7 +122,7 @@ describe('IDE: User opens IDE', () => { describe('path in URL is a directory', () => { beforeEach(async () => { - vm = ideHelper.createIdeComponent(container, { path: 'files/images' }); + vm = startWebIDE(container, { path: 'files/images' }); // wait for folders in left sidebar to be expanded await screen.findByText('images'); @@ -144,7 +145,7 @@ describe('IDE: User opens IDE', () => { describe("a file for path in url doesn't exist in the repo", () => { beforeEach(async () => { - vm = ideHelper.createIdeComponent(container, { path: 'abracadabra/hocus-focus.txt' }); + vm = startWebIDE(container, { path: 'abracadabra/hocus-focus.txt' }); // a new tab is open for hocus-focus.txt await findByText(document.querySelector('.multi-file-edit-pane'), 'hocus-focus.txt'); diff --git a/spec/frontend_integration/test_helpers/fixtures.js b/spec/frontend_integration/test_helpers/fixtures.js index 294a0d7709146..46946ed71f2ad 100644 --- a/spec/frontend_integration/test_helpers/fixtures.js +++ b/spec/frontend_integration/test_helpers/fixtures.js @@ -1,24 +1,40 @@ /* eslint-disable global-require, import/no-unresolved */ import { memoize } from 'lodash'; -import { readFileSync } from 'fs'; -import { join } from 'path'; -export const getProject = () => require('test_fixtures/api/projects/get.json'); -export const getEmptyProject = () => require('test_fixtures/api/projects/get_empty.json'); -export const getBranch = () => require('test_fixtures/api/projects/branches/get.json'); -export const getMergeRequests = () => require('test_fixtures/api/merge_requests/get.json'); -export const getRepositoryFiles = () => require('test_fixtures/projects_json/files.json'); +const createFactoryWithDefault = (fn, defaultValue) => () => { + try { + return fn(); + } catch { + return defaultValue; + } +}; -export const getBlobReadme = () => - readFileSync(require.resolve('test_fixtures/blob/text/README.md'), 'utf8'); -export const getBlobZip = () => - readFileSync(require.resolve('test_fixtures/blob/binary/Gemfile.zip'), 'utf8'); -export const getBlobImage = () => - readFileSync( - join(require.resolve('test_fixtures/blob/text/README.md'), '../..', 'images/logo-white.png'), - 'utf8', - ); +const factory = { + json: fn => createFactoryWithDefault(fn, { error: 'fixture not found' }), + text: fn => createFactoryWithDefault(fn, 'Hello world\nHow are you today?\n'), + binary: fn => createFactoryWithDefault(fn, ''), +}; -export const getPipelinesEmptyResponse = () => - require('test_fixtures/projects_json/pipelines_empty.json'); +export const getProject = factory.json(() => require('test_fixtures/api/projects/get.json')); +export const getEmptyProject = factory.json(() => + require('test_fixtures/api/projects/get_empty.json'), +); +export const getBranch = factory.json(() => + require('test_fixtures/api/projects/branches/get.json'), +); +export const getMergeRequests = factory.json(() => + require('test_fixtures/api/merge_requests/get.json'), +); +export const getRepositoryFiles = factory.json(() => + require('test_fixtures/projects_json/files.json'), +); +export const getPipelinesEmptyResponse = factory.json(() => + require('test_fixtures/projects_json/pipelines_empty.json'), +); export const getCommit = memoize(() => getBranch().commit); + +export const getBlobReadme = factory.text(() => require('test_fixtures/blob/text/README.md')); +export const getBlobZip = factory.binary(() => require('test_fixtures/blob/binary/Gemfile.zip')); +export const getBlobImage = factory.binary(() => + require('test_fixtures/blob/images/logo-white.png'), +); -- GitLab