mirror of https://github.com/artf/grapesjs.git
19 changed files with 898 additions and 859 deletions
@ -1,3 +1,4 @@ |
|||||
docs/**/*.md |
docs/**/*.md |
||||
dist/ |
dist/ |
||||
pnpm-lock.yaml |
pnpm-lock.yaml |
||||
|
packages/cli/src/template/**/*.* |
||||
@ -1,6 +1,3 @@ |
|||||
module.exports = { |
module.exports = { |
||||
presets: [ |
presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], |
||||
['@babel/preset-env', { targets: { node: 'current' } }], |
}; |
||||
'@babel/preset-typescript', |
|
||||
], |
|
||||
}; |
|
||||
|
|||||
@ -1,3 +1,3 @@ |
|||||
export { default as init } from './init'; |
export { default as init } from './init'; |
||||
export { default as build } from './build'; |
export { default as build } from './build'; |
||||
export { default as serve } from './serve'; |
export { default as serve } from './serve'; |
||||
|
|||||
@ -1,338 +1,359 @@ |
|||||
import { isFunction, isObject, isString, isUndefined, printRow, printError, log, ensureDir, normalizeJsonOpt, buildWebpackArgs, copyRecursiveSync, babelConfig, originalRequire, resolve, rootResolve } from "../src/utils"; |
import { |
||||
|
isFunction, |
||||
|
isObject, |
||||
|
isString, |
||||
|
isUndefined, |
||||
|
printRow, |
||||
|
printError, |
||||
|
log, |
||||
|
ensureDir, |
||||
|
normalizeJsonOpt, |
||||
|
buildWebpackArgs, |
||||
|
copyRecursiveSync, |
||||
|
babelConfig, |
||||
|
originalRequire, |
||||
|
resolve, |
||||
|
rootResolve, |
||||
|
} from '../src/utils'; |
||||
import chalk from 'chalk'; |
import chalk from 'chalk'; |
||||
import fs from 'fs'; |
import fs from 'fs'; |
||||
import path from 'path'; |
import path from 'path'; |
||||
import * as process from 'process'; |
import * as process from 'process'; |
||||
|
|
||||
const typeTestValues = { |
const typeTestValues = { |
||||
undefinedValue: undefined, |
undefinedValue: undefined, |
||||
nullValue: null, |
nullValue: null, |
||||
stringValue: 'hello', |
stringValue: 'hello', |
||||
emptyObject: {}, |
emptyObject: {}, |
||||
nonEmptyObject: { key: 'value' }, |
nonEmptyObject: { key: 'value' }, |
||||
emptyArray: [], |
emptyArray: [], |
||||
functionValue: () => { }, |
functionValue: () => {}, |
||||
numberValue: 42, |
numberValue: 42, |
||||
booleanValue: true, |
booleanValue: true, |
||||
dateValue: new Date(), |
dateValue: new Date(), |
||||
}; |
}; |
||||
|
|
||||
function runTypeCheck(typeCheckFunction: (value: any) => boolean) { |
function runTypeCheck(typeCheckFunction: (value: any) => boolean) { |
||||
const keysWithPassingTypeChecks = Object.keys(typeTestValues).filter(key => { |
const keysWithPassingTypeChecks = Object.keys(typeTestValues).filter((key) => { |
||||
const value = typeTestValues[key]; |
const value = typeTestValues[key]; |
||||
return typeCheckFunction(value); |
return typeCheckFunction(value); |
||||
}); |
}); |
||||
|
|
||||
return keysWithPassingTypeChecks; |
return keysWithPassingTypeChecks; |
||||
} |
} |
||||
|
|
||||
jest.mock('fs'); |
jest.mock('fs'); |
||||
jest.mock('fs/promises'); |
jest.mock('fs/promises'); |
||||
|
|
||||
describe('utils', () => { |
describe('utils', () => { |
||||
afterEach(() => { |
afterEach(() => { |
||||
jest.clearAllMocks(); |
jest.clearAllMocks(); |
||||
|
}); |
||||
|
|
||||
|
describe('isString', () => { |
||||
|
it('should correctly identify strings', () => { |
||||
|
const result = runTypeCheck(isString); |
||||
|
expect(result).toEqual(['stringValue']); |
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
describe('isString', () => { |
describe('isUndefined', () => { |
||||
it('should correctly identify strings', () => { |
it('should correctly identify undefined values', () => { |
||||
const result = runTypeCheck(isString); |
const result = runTypeCheck(isUndefined); |
||||
expect(result).toEqual(['stringValue']); |
expect(result).toEqual(['undefinedValue']); |
||||
}); |
|
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
describe('isUndefined', () => { |
describe('isFunction', () => { |
||||
it('should correctly identify undefined values', () => { |
it('should correctly identify functions', () => { |
||||
const result = runTypeCheck(isUndefined); |
const result = runTypeCheck(isFunction); |
||||
expect(result).toEqual(['undefinedValue']); |
expect(result).toEqual(['functionValue']); |
||||
}); |
|
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
describe('isFunction', () => { |
describe('isObject', () => { |
||||
it('should correctly identify functions', () => { |
it('should correctly identify objects', () => { |
||||
const result = runTypeCheck(isFunction); |
const result = runTypeCheck(isObject); |
||||
expect(result).toEqual(['functionValue']); |
expect(result).toEqual(['emptyObject', 'nonEmptyObject', 'dateValue']); |
||||
}); |
|
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
|
describe('printRow', () => { |
||||
|
// TODO: We should refactor the function to make lineDown a boolean not a number
|
||||
|
it('should console.log the given string with the specified color and line breaks', () => { |
||||
|
const str = 'Test string'; |
||||
|
const color = 'blue'; |
||||
|
const lineDown = 1; |
||||
|
|
||||
|
console.log = jest.fn(); |
||||
|
|
||||
|
printRow(str, { color, lineDown }); |
||||
|
|
||||
describe('isObject', () => { |
expect(console.log).toHaveBeenCalledTimes(3); // 1 for empty line, 1 for colored string, 1 for line break
|
||||
it('should correctly identify objects', () => { |
expect(console.log.mock.calls[1][0]).toEqual(chalk[color].bold(str)); |
||||
const result = runTypeCheck(isObject); |
|
||||
expect(result).toEqual(['emptyObject', 'nonEmptyObject', 'dateValue']); |
|
||||
}); |
|
||||
}); |
}); |
||||
|
|
||||
|
it('should not add a line break if lineDown is false', () => { |
||||
|
const str = 'Test string'; |
||||
|
const color = 'green'; |
||||
|
const lineDown = 0; |
||||
|
|
||||
describe('printRow', () => { |
console.log = jest.fn(); |
||||
// TODO: We should refactor the function to make lineDown a boolean not a number
|
|
||||
it('should console.log the given string with the specified color and line breaks', () => { |
|
||||
const str = 'Test string'; |
|
||||
const color = 'blue'; |
|
||||
const lineDown = 1; |
|
||||
|
|
||||
console.log = jest.fn(); |
printRow(str, { color, lineDown }); |
||||
|
|
||||
printRow(str, { color, lineDown }); |
expect(console.log).toHaveBeenCalledTimes(2); // 1 for empty line, 1 for colored string
|
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('printError', () => { |
||||
|
it('should print the given string in red', () => { |
||||
|
const str = 'Error message'; |
||||
|
|
||||
expect(console.log).toHaveBeenCalledTimes(3); // 1 for empty line, 1 for colored string, 1 for line break
|
console.log = jest.fn(); |
||||
expect(console.log.mock.calls[1][0]).toEqual(chalk[color].bold(str)); |
|
||||
}); |
|
||||
|
|
||||
it('should not add a line break if lineDown is false', () => { |
printError(str); |
||||
const str = 'Test string'; |
|
||||
const color = 'green'; |
expect(console.log).toHaveBeenCalledTimes(3); // 1 for empty line, 1 for red string, 1 for line break
|
||||
const lineDown = 0; |
expect(console.log.mock.calls[1][0]).toEqual(chalk.red.bold(str)); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
console.log = jest.fn(); |
describe('log', () => { |
||||
|
it('should call console.log with the given arguments', () => { |
||||
|
const arg1 = 'Argument 1'; |
||||
|
const arg2 = 'Argument 2'; |
||||
|
|
||||
printRow(str, { color, lineDown }); |
console.log = jest.fn(); |
||||
|
|
||||
expect(console.log).toHaveBeenCalledTimes(2); // 1 for empty line, 1 for colored string
|
log(arg1, arg2); |
||||
}); |
|
||||
|
expect(console.log).toHaveBeenCalledWith(arg1, arg2); |
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
describe('printError', () => { |
describe('ensureDir', () => { |
||||
it('should print the given string in red', () => { |
it('should return true when the directory already exists', () => { |
||||
const str = 'Error message'; |
(fs.existsSync as jest.Mock).mockReturnValue(true); |
||||
|
|
||||
console.log = jest.fn(); |
const result = ensureDir('/path/to/file.txt'); |
||||
|
expect(result).toBe(true); |
||||
|
expect(fs.existsSync).toHaveBeenCalledWith('/path/to'); |
||||
|
expect(fs.mkdirSync).not.toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
printError(str); |
it('should create the directory when it does not exist', () => { |
||||
|
(fs.existsSync as jest.Mock).mockReturnValueOnce(false).mockReturnValueOnce(true); |
||||
|
|
||||
expect(console.log).toHaveBeenCalledTimes(3); // 1 for empty line, 1 for red string, 1 for line break
|
const result = ensureDir('/path/to/file.txt'); |
||||
expect(console.log.mock.calls[1][0]).toEqual(chalk.red.bold(str)); |
expect(result).toBe(true); |
||||
}); |
expect(fs.existsSync).toHaveBeenCalledWith('/path/to'); |
||||
|
expect(fs.mkdirSync).toHaveBeenCalledWith('/path/to'); |
||||
}); |
}); |
||||
|
|
||||
describe('log', () => { |
it('should create parent directories recursively when they do not exist', () => { |
||||
it('should call console.log with the given arguments', () => { |
(fs.existsSync as jest.Mock) |
||||
const arg1 = 'Argument 1'; |
.mockReturnValueOnce(false) // Check /path/to (does not exist)
|
||||
const arg2 = 'Argument 2'; |
.mockReturnValueOnce(false) // Check /path (does not exist)
|
||||
|
.mockReturnValueOnce(true); // Check / (root, exists)
|
||||
|
|
||||
console.log = jest.fn(); |
const result = ensureDir('/path/to/file.txt'); |
||||
|
expect(result).toBe(true); |
||||
|
expect(fs.existsSync).toHaveBeenCalledTimes(3); // /path/to, /path, /
|
||||
|
expect(fs.mkdirSync).toHaveBeenCalledTimes(2); // /path, /path/to
|
||||
|
}); |
||||
|
}); |
||||
|
|
||||
log(arg1, arg2); |
describe('normalizeJsonOpt', () => { |
||||
|
it('should return the object if the option is already an object', () => { |
||||
|
const opts = { babel: { presets: ['@babel/preset-env'] } }; |
||||
|
const result = normalizeJsonOpt(opts, 'babel'); |
||||
|
expect(result).toEqual(opts.babel); |
||||
|
}); |
||||
|
|
||||
expect(console.log).toHaveBeenCalledWith(arg1, arg2); |
it('should parse and return the object if the option is a valid JSON string', () => { |
||||
}); |
const opts = { babel: '{"presets":["@babel/preset-env"]}' }; |
||||
|
const result = normalizeJsonOpt(opts, 'babel'); |
||||
|
expect(result).toEqual({ presets: ['@babel/preset-env'] }); |
||||
}); |
}); |
||||
|
|
||||
describe('ensureDir', () => { |
it('should return an empty object if the option is an invalid JSON string', () => { |
||||
it('should return true when the directory already exists', () => { |
const opts = { babel: '{"presets":["@babel/preset-env"]' }; // Invalid JSON
|
||||
(fs.existsSync as jest.Mock).mockReturnValue(true); |
const result = normalizeJsonOpt(opts, 'babel'); |
||||
|
expect(result).toEqual({}); |
||||
const result = ensureDir('/path/to/file.txt'); |
|
||||
expect(result).toBe(true); |
|
||||
expect(fs.existsSync).toHaveBeenCalledWith('/path/to'); |
|
||||
expect(fs.mkdirSync).not.toHaveBeenCalled(); |
|
||||
}); |
|
||||
|
|
||||
it('should create the directory when it does not exist', () => { |
|
||||
(fs.existsSync as jest.Mock).mockReturnValueOnce(false).mockReturnValueOnce(true); |
|
||||
|
|
||||
const result = ensureDir('/path/to/file.txt'); |
|
||||
expect(result).toBe(true); |
|
||||
expect(fs.existsSync).toHaveBeenCalledWith('/path/to'); |
|
||||
expect(fs.mkdirSync).toHaveBeenCalledWith('/path/to'); |
|
||||
}); |
|
||||
|
|
||||
it('should create parent directories recursively when they do not exist', () => { |
|
||||
(fs.existsSync as jest.Mock) |
|
||||
.mockReturnValueOnce(false) // Check /path/to (does not exist)
|
|
||||
.mockReturnValueOnce(false) // Check /path (does not exist)
|
|
||||
.mockReturnValueOnce(true); // Check / (root, exists)
|
|
||||
|
|
||||
const result = ensureDir('/path/to/file.txt'); |
|
||||
expect(result).toBe(true); |
|
||||
expect(fs.existsSync).toHaveBeenCalledTimes(3); // /path/to, /path, /
|
|
||||
expect(fs.mkdirSync).toHaveBeenCalledTimes(2); // /path, /path/to
|
|
||||
}); |
|
||||
}); |
}); |
||||
|
|
||||
describe('normalizeJsonOpt', () => { |
it('should return an empty object if the option is not provided', () => { |
||||
it('should return the object if the option is already an object', () => { |
const opts = {}; |
||||
const opts = { babel: { presets: ['@babel/preset-env'] } }; |
const result = normalizeJsonOpt(opts, 'babel'); |
||||
const result = normalizeJsonOpt(opts, 'babel'); |
expect(result).toEqual({}); |
||||
expect(result).toEqual(opts.babel); |
}); |
||||
}); |
}); |
||||
|
|
||||
it('should parse and return the object if the option is a valid JSON string', () => { |
describe('buildWebpackArgs', () => { |
||||
const opts = { babel: '{"presets":["@babel/preset-env"]}' }; |
it('should return the options with normalized JSON options for babel and htmlWebpack', () => { |
||||
const result = normalizeJsonOpt(opts, 'babel'); |
const opts = { |
||||
expect(result).toEqual({ presets: ['@babel/preset-env'] }); |
babel: '{"presets":["@babel/preset-env"]}', |
||||
}); |
htmlWebpack: '{"template":"./src/index.html"}', |
||||
|
otherOption: 'someValue', |
||||
it('should return an empty object if the option is an invalid JSON string', () => { |
}; |
||||
const opts = { babel: '{"presets":["@babel/preset-env"]' }; // Invalid JSON
|
|
||||
const result = normalizeJsonOpt(opts, 'babel'); |
const result = buildWebpackArgs(opts); |
||||
expect(result).toEqual({}); |
expect(result).toEqual({ |
||||
}); |
babel: { presets: ['@babel/preset-env'] }, |
||||
|
htmlWebpack: { template: './src/index.html' }, |
||||
it('should return an empty object if the option is not provided', () => { |
otherOption: 'someValue', |
||||
const opts = {}; |
}); |
||||
const result = normalizeJsonOpt(opts, 'babel'); |
|
||||
expect(result).toEqual({}); |
|
||||
}); |
|
||||
}); |
}); |
||||
|
|
||||
describe('buildWebpackArgs', () => { |
it('should return empty objects for babel and htmlWebpack if they are invalid JSON strings', () => { |
||||
it('should return the options with normalized JSON options for babel and htmlWebpack', () => { |
const opts = { |
||||
const opts = { |
babel: '{"presets":["@babel/preset-env"]', // Invalid JSON
|
||||
babel: '{"presets":["@babel/preset-env"]}', |
htmlWebpack: '{"template":"./src/index.html', // Invalid JSON
|
||||
htmlWebpack: '{"template":"./src/index.html"}', |
}; |
||||
otherOption: 'someValue' |
|
||||
}; |
const result = buildWebpackArgs(opts); |
||||
|
expect(result).toEqual({ |
||||
const result = buildWebpackArgs(opts); |
babel: {}, |
||||
expect(result).toEqual({ |
htmlWebpack: {}, |
||||
babel: { presets: ['@babel/preset-env'] }, |
}); |
||||
htmlWebpack: { template: './src/index.html' }, |
|
||||
otherOption: 'someValue', |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
it('should return empty objects for babel and htmlWebpack if they are invalid JSON strings', () => { |
|
||||
const opts = { |
|
||||
babel: '{"presets":["@babel/preset-env"]', // Invalid JSON
|
|
||||
htmlWebpack: '{"template":"./src/index.html', // Invalid JSON
|
|
||||
}; |
|
||||
|
|
||||
const result = buildWebpackArgs(opts); |
|
||||
expect(result).toEqual({ |
|
||||
babel: {}, |
|
||||
htmlWebpack: {}, |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
it('should return the original objects if babel and htmlWebpack are already objects', () => { |
|
||||
const opts = { |
|
||||
babel: { presets: ['@babel/preset-env'] }, |
|
||||
htmlWebpack: { template: './src/index.html' }, |
|
||||
}; |
|
||||
|
|
||||
const result = buildWebpackArgs(opts); |
|
||||
expect(result).toEqual({ |
|
||||
babel: opts.babel, |
|
||||
htmlWebpack: opts.htmlWebpack, |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
it('should handle missing babel and htmlWebpack keys gracefully', () => { |
|
||||
const opts = { otherOption: 'someValue' }; |
|
||||
|
|
||||
const result = buildWebpackArgs(opts); |
|
||||
expect(result).toEqual({ |
|
||||
babel: {}, |
|
||||
htmlWebpack: {}, |
|
||||
otherOption: 'someValue', |
|
||||
}); |
|
||||
}); |
|
||||
}); |
}); |
||||
|
|
||||
describe('copyRecursiveSync', () => { |
it('should return the original objects if babel and htmlWebpack are already objects', () => { |
||||
// TODO: Maybe this test case is a bit complex and we should think of an easier solution
|
const opts = { |
||||
it('should copy a directory and its contents recursively', () => { |
babel: { presets: ['@babel/preset-env'] }, |
||||
/** |
htmlWebpack: { template: './src/index.html' }, |
||||
* First call: Mock as a directory with two files |
}; |
||||
* Subsequent calls: Mock as a file |
|
||||
*/ |
const result = buildWebpackArgs(opts); |
||||
const existsSyncMock = (fs.existsSync as jest.Mock).mockReturnValue(true); |
expect(result).toEqual({ |
||||
const statSyncMock = (fs.statSync as jest.Mock).mockReturnValueOnce({ isDirectory: () => true }).mockReturnValue({ isDirectory: () => false }); |
babel: opts.babel, |
||||
const readdirSyncMock = (fs.readdirSync as jest.Mock).mockReturnValueOnce(['file1.txt', 'file2.txt']).mockReturnValue([]); |
htmlWebpack: opts.htmlWebpack, |
||||
const copyFileSyncMock = (fs.copyFileSync as jest.Mock).mockImplementation(() => { }); |
}); |
||||
|
|
||||
copyRecursiveSync('/src', '/dest'); |
|
||||
|
|
||||
expect(existsSyncMock).toHaveBeenCalledWith('/src'); |
|
||||
expect(statSyncMock).toHaveBeenCalledWith('/src'); |
|
||||
expect(fs.mkdirSync).toHaveBeenCalledWith('/dest'); |
|
||||
expect(readdirSyncMock).toHaveBeenCalledWith('/src'); |
|
||||
expect(copyFileSyncMock).toHaveBeenCalledWith(path.normalize('/src/file1.txt'), path.normalize('/dest/file1.txt')); |
|
||||
expect(copyFileSyncMock).toHaveBeenCalledWith(path.normalize('/src/file2.txt'), path.normalize('/dest/file2.txt')); |
|
||||
}); |
|
||||
|
|
||||
it('should copy a file when source is a file', () => { |
|
||||
(fs.existsSync as jest.Mock).mockReturnValue(true); |
|
||||
(fs.statSync as jest.Mock).mockReturnValue({ isDirectory: () => false }); |
|
||||
|
|
||||
copyRecursiveSync('/src/file.txt', '/dest/file.txt'); |
|
||||
|
|
||||
expect(fs.existsSync).toHaveBeenCalledWith('/src/file.txt'); |
|
||||
expect(fs.statSync).toHaveBeenCalledWith('/src/file.txt'); |
|
||||
expect(fs.copyFileSync).toHaveBeenCalledWith('/src/file.txt', '/dest/file.txt'); |
|
||||
}); |
|
||||
|
|
||||
// Maybe we can change the behavior to throw an error if the `src` doesn't exist
|
|
||||
it('should do nothing when source does not exist', () => { |
|
||||
(fs.existsSync as jest.Mock).mockReturnValue(false); |
|
||||
|
|
||||
copyRecursiveSync('/src/file.txt', '/dest/file.txt'); |
|
||||
|
|
||||
expect(fs.existsSync).toHaveBeenCalledWith('/src/file.txt'); |
|
||||
expect(fs.statSync).not.toHaveBeenCalled(); |
|
||||
expect(fs.mkdirSync).not.toHaveBeenCalled(); |
|
||||
expect(fs.copyFileSync).not.toHaveBeenCalled(); |
|
||||
}); |
|
||||
}); |
}); |
||||
|
|
||||
describe('rootResolve', () => { |
it('should handle missing babel and htmlWebpack keys gracefully', () => { |
||||
it('should resolve a relative path to an absolute path', () => { |
const opts = { otherOption: 'someValue' }; |
||||
const result = rootResolve('src/index.js'); |
|
||||
|
|
||||
expect(result).toBe(path.join(process.cwd(), 'src/index.js')); |
const result = buildWebpackArgs(opts); |
||||
}); |
expect(result).toEqual({ |
||||
|
babel: {}, |
||||
|
htmlWebpack: {}, |
||||
|
otherOption: 'someValue', |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('copyRecursiveSync', () => { |
||||
|
// TODO: Maybe this test case is a bit complex and we should think of an easier solution
|
||||
|
it('should copy a directory and its contents recursively', () => { |
||||
|
/** |
||||
|
* First call: Mock as a directory with two files |
||||
|
* Subsequent calls: Mock as a file |
||||
|
*/ |
||||
|
const existsSyncMock = (fs.existsSync as jest.Mock).mockReturnValue(true); |
||||
|
const statSyncMock = (fs.statSync as jest.Mock) |
||||
|
.mockReturnValueOnce({ isDirectory: () => true }) |
||||
|
.mockReturnValue({ isDirectory: () => false }); |
||||
|
const readdirSyncMock = (fs.readdirSync as jest.Mock) |
||||
|
.mockReturnValueOnce(['file1.txt', 'file2.txt']) |
||||
|
.mockReturnValue([]); |
||||
|
const copyFileSyncMock = (fs.copyFileSync as jest.Mock).mockImplementation(() => {}); |
||||
|
|
||||
|
copyRecursiveSync('/src', '/dest'); |
||||
|
|
||||
|
expect(existsSyncMock).toHaveBeenCalledWith('/src'); |
||||
|
expect(statSyncMock).toHaveBeenCalledWith('/src'); |
||||
|
expect(fs.mkdirSync).toHaveBeenCalledWith('/dest'); |
||||
|
expect(readdirSyncMock).toHaveBeenCalledWith('/src'); |
||||
|
expect(copyFileSyncMock).toHaveBeenCalledWith( |
||||
|
path.normalize('/src/file1.txt'), |
||||
|
path.normalize('/dest/file1.txt'), |
||||
|
); |
||||
|
expect(copyFileSyncMock).toHaveBeenCalledWith( |
||||
|
path.normalize('/src/file2.txt'), |
||||
|
path.normalize('/dest/file2.txt'), |
||||
|
); |
||||
}); |
}); |
||||
|
|
||||
describe('originalRequire', () => { |
it('should copy a file when source is a file', () => { |
||||
it('should return the original require.resolve function', () => { |
(fs.existsSync as jest.Mock).mockReturnValue(true); |
||||
const originalRequireMock = jest.fn(); |
(fs.statSync as jest.Mock).mockReturnValue({ isDirectory: () => false }); |
||||
global.__non_webpack_require__ = originalRequireMock; |
|
||||
|
|
||||
const result = originalRequire(); |
copyRecursiveSync('/src/file.txt', '/dest/file.txt'); |
||||
|
|
||||
expect(result).toBe(originalRequireMock); |
expect(fs.existsSync).toHaveBeenCalledWith('/src/file.txt'); |
||||
}); |
expect(fs.statSync).toHaveBeenCalledWith('/src/file.txt'); |
||||
|
expect(fs.copyFileSync).toHaveBeenCalledWith('/src/file.txt', '/dest/file.txt'); |
||||
}); |
}); |
||||
|
|
||||
describe('resolve', () => { |
// Maybe we can change the behavior to throw an error if the `src` doesn't exist
|
||||
it('should resolve a module path using the original require.resolve', () => { |
it('should do nothing when source does not exist', () => { |
||||
const originalRequireMock = { |
(fs.existsSync as jest.Mock).mockReturnValue(false); |
||||
resolve: jest.fn().mockReturnValue('resolved/path'), |
|
||||
}; |
|
||||
global.__non_webpack_require__ = originalRequireMock; |
|
||||
|
|
||||
const result = resolve('my-module'); |
copyRecursiveSync('/src/file.txt', '/dest/file.txt'); |
||||
|
|
||||
expect(result).toBe('resolved/path'); |
expect(fs.existsSync).toHaveBeenCalledWith('/src/file.txt'); |
||||
expect(originalRequireMock.resolve).toHaveBeenCalledWith('my-module'); |
expect(fs.statSync).not.toHaveBeenCalled(); |
||||
}); |
expect(fs.mkdirSync).not.toHaveBeenCalled(); |
||||
|
expect(fs.copyFileSync).not.toHaveBeenCalled(); |
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
|
describe('rootResolve', () => { |
||||
|
it('should resolve a relative path to an absolute path', () => { |
||||
|
const result = rootResolve('src/index.js'); |
||||
|
|
||||
|
expect(result).toBe(path.join(process.cwd(), 'src/index.js')); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('originalRequire', () => { |
||||
|
it('should return the original require.resolve function', () => { |
||||
|
const originalRequireMock = jest.fn(); |
||||
|
global.__non_webpack_require__ = originalRequireMock; |
||||
|
|
||||
|
const result = originalRequire(); |
||||
|
|
||||
|
expect(result).toBe(originalRequireMock); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('resolve', () => { |
||||
|
it('should resolve a module path using the original require.resolve', () => { |
||||
|
const originalRequireMock = { |
||||
|
resolve: jest.fn().mockReturnValue('resolved/path'), |
||||
|
}; |
||||
|
global.__non_webpack_require__ = originalRequireMock; |
||||
|
|
||||
|
const result = resolve('my-module'); |
||||
|
|
||||
|
expect(result).toBe('resolved/path'); |
||||
|
expect(originalRequireMock.resolve).toHaveBeenCalledWith('my-module'); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('babelConfig', () => { |
||||
|
afterEach(() => { |
||||
|
jest.restoreAllMocks(); |
||||
|
}); |
||||
|
|
||||
|
it('should return a Babel configuration object with specified presets and plugins', () => { |
||||
|
const result = babelConfig(); |
||||
|
|
||||
|
expect(result).toEqual({ |
||||
|
presets: [[resolve('@babel/preset-env'), { targets: undefined }]], |
||||
|
plugins: [resolve('@babel/plugin-transform-runtime')], |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it('should include the specified targets in the Babel configuration', () => { |
||||
|
const result = babelConfig({ targets: 'node 14' }); |
||||
|
|
||||
describe('babelConfig', () => { |
expect(result).toEqual({ |
||||
afterEach(() => { |
presets: [[resolve('@babel/preset-env'), { targets: 'node 14' }]], |
||||
jest.restoreAllMocks(); |
plugins: [resolve('@babel/plugin-transform-runtime')], |
||||
}); |
}); |
||||
|
|
||||
it('should return a Babel configuration object with specified presets and plugins', () => { |
|
||||
const result = babelConfig(); |
|
||||
|
|
||||
expect(result).toEqual({ |
|
||||
presets: [ |
|
||||
[resolve('@babel/preset-env'), { targets: undefined }], |
|
||||
], |
|
||||
plugins: [resolve('@babel/plugin-transform-runtime')], |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
it('should include the specified targets in the Babel configuration', () => { |
|
||||
const result = babelConfig({ targets: 'node 14' }); |
|
||||
|
|
||||
expect(result).toEqual({ |
|
||||
presets: [ |
|
||||
[resolve('@babel/preset-env'), { targets: 'node 14' }], |
|
||||
], |
|
||||
plugins: [resolve('@babel/plugin-transform-runtime')], |
|
||||
}); |
|
||||
}); |
|
||||
}); |
}); |
||||
}); |
}); |
||||
|
}); |
||||
|
|||||
Loading…
Reference in new issue