diff options
Diffstat (limited to 'spec/frontend/mocks/mocks_helper.js')
-rw-r--r-- | spec/frontend/mocks/mocks_helper.js | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/spec/frontend/mocks/mocks_helper.js b/spec/frontend/mocks/mocks_helper.js new file mode 100644 index 00000000000..21c032cd3c9 --- /dev/null +++ b/spec/frontend/mocks/mocks_helper.js @@ -0,0 +1,60 @@ +/** + * @module + * + * This module implements auto-injected manual mocks that are cleaner than Jest's approach. + * + * See https://docs.gitlab.com/ee/development/testing_guide/frontend_testing.html + */ + +import fs from 'fs'; +import path from 'path'; + +import readdir from 'readdir-enhanced'; + +const MAX_DEPTH = 20; +const prefixMap = [ + // E.g. the mock ce/foo/bar maps to require path ~/foo/bar + { mocksRoot: 'ce', requirePrefix: '~' }, + // { mocksRoot: 'ee', requirePrefix: 'ee' }, // We'll deal with EE-specific mocks later + { mocksRoot: 'node', requirePrefix: '' }, + // { mocksRoot: 'virtual', requirePrefix: '' }, // We'll deal with virtual mocks later +]; + +const mockFileFilter = stats => stats.isFile() && stats.path.endsWith('.js'); + +const getMockFiles = root => readdir.sync(root, { deep: MAX_DEPTH, filter: mockFileFilter }); + +// Function that performs setting a mock. This has to be overridden by the unit test, because +// jest.setMock can't be overwritten across files. +// Use require() because jest.setMock expects the CommonJS exports object +const defaultSetMock = (srcPath, mockPath) => + jest.mock(srcPath, () => jest.requireActual(mockPath)); + +// eslint-disable-next-line import/prefer-default-export +export const setupManualMocks = function setupManualMocks(setMock = defaultSetMock) { + prefixMap.forEach(({ mocksRoot, requirePrefix }) => { + const mocksRootAbsolute = path.join(__dirname, mocksRoot); + if (!fs.existsSync(mocksRootAbsolute)) { + return; + } + + getMockFiles(path.join(__dirname, mocksRoot)).forEach(mockPath => { + const mockPathNoExt = mockPath.substring(0, mockPath.length - path.extname(mockPath).length); + const sourcePath = path.join(requirePrefix, mockPathNoExt); + const mockPathRelative = `./${path.join(mocksRoot, mockPathNoExt)}`; + + try { + setMock(sourcePath, mockPathRelative); + } catch (e) { + if (e.message.includes('Could not locate module')) { + // The corresponding mocked module doesn't exist. Raise a better error. + // Eventualy, we may support virtual mocks (mocks whose path doesn't directly correspond + // to a module, like with the `ee_else_ce` prefix). + throw new Error( + `A manual mock was defined for module ${sourcePath}, but the module doesn't exist!`, + ); + } + } + }); + }); +}; |