From 8db5a898e4429a645304cded88fe63622cd0fa89 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Tue, 23 Jul 2019 14:48:56 +0300 Subject: [PATCH] test: refactor --- src/processPattern.js | 2 + test/CopyPlugin.test.js | 1028 +++++------------------------ test/cache-option.test.js | 249 +++++++ test/flatten-option.test.js | 147 +++++ test/force-option.test.js | 237 +++++++ test/ignore-option.test.js | 186 ++++++ test/test-option.test.js | 73 ++ test/transform-option.test.js | 184 ++++++ test/transformPath-option.test.js | 22 +- test/utils/run.js | 17 +- 10 files changed, 1269 insertions(+), 876 deletions(-) create mode 100644 test/cache-option.test.js create mode 100644 test/flatten-option.test.js create mode 100644 test/force-option.test.js create mode 100644 test/ignore-option.test.js create mode 100644 test/test-option.test.js create mode 100644 test/transform-option.test.js diff --git a/src/processPattern.js b/src/processPattern.js index 6cec72ba..b881b624 100644 --- a/src/processPattern.js +++ b/src/processPattern.js @@ -12,6 +12,8 @@ export default function processPattern(globalRef, pattern) { { cwd: pattern.context, follow: true, + // Todo in next major release + // dot: true }, pattern.globOptions || {} ); diff --git a/test/CopyPlugin.test.js b/test/CopyPlugin.test.js index d54b8420..ba98a8db 100644 --- a/test/CopyPlugin.test.js +++ b/test/CopyPlugin.test.js @@ -1,10 +1,6 @@ import fs from 'fs'; import path from 'path'; -import zlib from 'zlib'; -import findCacheDir from 'find-cache-dir'; -import cacache from 'cacache'; -import isGzip from 'is-gzip'; import mkdirp from 'mkdirp'; import CopyPlugin from '../src/index'; @@ -12,7 +8,7 @@ import CopyPlugin from '../src/index'; import removeIllegalCharacterForWindows from './utils/removeIllegalCharacterForWindows'; import { MockCompiler, MockCompilerNoStat } from './utils/mocks'; -import { run, runEmit, runForce, runChange } from './utils/run'; +import { run, runEmit, runChange } from './utils/run'; const BUILD_DIR = path.join(__dirname, 'build'); const HELPER_DIR = path.join(__dirname, 'helpers'); @@ -256,26 +252,6 @@ describe('apply function', () => { .catch(done); }); - it('can use a glob to flatten multiple files in a relative context to a non-root directory', (done) => { - runEmit({ - expectedAssetKeys: [ - 'nested/deepnested.txt', - 'nested/directoryfile.txt', - 'nested/nestedfile.txt', - ], - patterns: [ - { - context: 'directory', - flatten: true, - from: '**/*', - to: 'nested', - }, - ], - }) - .then(done) - .catch(done); - }); - it('can use a glob to move multiple files in a different absolute context to a non-root directory', (done) => { runEmit({ expectedAssetKeys: [ @@ -362,27 +338,6 @@ describe('apply function', () => { .catch(done); }); - it('can flatten or normalize glob matches', (done) => { - runEmit({ - expectedAssetKeys: [ - '[!]-hello.txt', - '[special?directory]-(special-*file).txt', - '[special?directory]-directoryfile.txt', - 'dir (86)-file.txt', - 'directory-directoryfile.txt', - ], - patterns: [ - { - from: '*/*.*', - test: `([^\\${path.sep}]+)\\${path.sep}([^\\${path.sep}]+)\\.\\w+$`, - to: '[1]-[2].[ext]', - }, - ], - }) - .then(done) - .catch(done); - }); - it('adds the context directory to the watch list when using glob', (done) => { run({ patterns: [ @@ -460,27 +415,6 @@ describe('apply function', () => { .catch(done); }); - it('can transform a file', (done) => { - runEmit({ - expectedAssetKeys: ['file.txt'], - expectedAssetContent: { - 'file.txt': 'newchanged', - }, - patterns: [ - { - from: 'file.txt', - transform(content, absoluteFrom) { - expect(absoluteFrom).toBe(path.join(HELPER_DIR, 'file.txt')); - - return `${content}changed`; - }, - }, - ], - }) - .then(done) - .catch(done); - }); - it('warns when file not found', (done) => { runEmit({ expectedAssetKeys: [], @@ -520,24 +454,6 @@ describe('apply function', () => { .catch(done); }); - it('warns when tranform failed', (done) => { - runEmit({ - expectedAssetKeys: [], - expectedErrors: ['a failure happened'], - patterns: [ - { - from: 'file.txt', - transform() { - // eslint-disable-next-line no-throw-literal - throw 'a failure happened'; - }, - }, - ], - }) - .then(done) - .catch(done); - }); - it('warns when pattern is empty', (done) => { runEmit({ expectedAssetKeys: [ @@ -878,39 +794,6 @@ describe('apply function', () => { .catch(done); }); - it("won't overwrite a file already in the compilation", (done) => { - runForce({ - existingAsset: 'file.txt', - expectedAssetContent: { - 'file.txt': 'existing', - }, - patterns: [ - { - from: 'file.txt', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('can force overwrite of a file already in the compilation', (done) => { - runForce({ - existingAsset: 'file.txt', - expectedAssetContent: { - 'file.txt': 'new', - }, - patterns: [ - { - force: true, - from: 'file.txt', - }, - ], - }) - .then(done) - .catch(done); - }); - it('adds the file to the watch list', (done) => { run({ patterns: [ @@ -930,50 +813,6 @@ describe('apply function', () => { .catch(done); }); - it('only include files that have changed', (done) => { - runChange({ - expectedAssetKeys: ['tempfile1.txt'], - newFileLoc1: path.join(HELPER_DIR, 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt'), - patterns: [ - { - from: 'tempfile1.txt', - }, - { - from: 'tempfile2.txt', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores files in pattern', (done) => { - runEmit({ - expectedAssetKeys: [ - '[!]/hello.txt', - 'binextension.bin', - 'dir (86)/nesteddir/deepnesteddir/deepnesteddir.txt', - 'dir (86)/nesteddir/nestedfile.txt', - 'directory/directoryfile.txt', - 'directory/nested/deep-nested/deepnested.txt', - 'directory/nested/nestedfile.txt', - '[special?directory]/directoryfile.txt', - '[special?directory]/(special-*file).txt', - '[special?directory]/nested/nestedfile.txt', - 'noextension', - ], - patterns: [ - { - from: '**/*', - ignore: ['file.*', 'file-in-nested-directory.*'], - }, - ], - }) - .then(done) - .catch(done); - }); - it('allows pattern to contain name, hash or ext', (done) => { runEmit({ expectedAssetKeys: ['directory/directoryfile-22af64.txt'], @@ -1030,27 +869,6 @@ describe('apply function', () => { .catch(done); }); - it('transform with promise', (done) => { - runEmit({ - expectedAssetKeys: ['file.txt'], - expectedAssetContent: { - 'file.txt': 'newchanged!', - }, - patterns: [ - { - from: 'file.txt', - transform(content) { - return new Promise((resolve) => { - resolve(`${content}changed!`); - }); - }, - }, - ], - }) - .then(done) - .catch(done); - }); - it('same file to multiple targets', (done) => { runEmit({ expectedAssetKeys: ['first/file.txt', 'second/file.txt'], @@ -1215,26 +1033,6 @@ describe('apply function', () => { .catch(done); }); - it("can flatten a directory's contents to a new directory", (done) => { - runEmit({ - expectedAssetKeys: [ - 'newdirectory/.dottedfile', - 'newdirectory/deepnested.txt', - 'newdirectory/directoryfile.txt', - 'newdirectory/nestedfile.txt', - ], - patterns: [ - { - flatten: true, - from: 'directory', - to: 'newdirectory', - }, - ], - }) - .then(done) - .catch(done); - }); - it("can move a directory's contents to a new directory using an absolute to", (done) => { runEmit({ expectedAssetKeys: [ @@ -1303,39 +1101,6 @@ describe('apply function', () => { .catch(done); }); - it("won't overwrite a file already in the compilation", (done) => { - runForce({ - existingAsset: 'directoryfile.txt', - expectedAssetContent: { - 'directoryfile.txt': 'existing', - }, - patterns: [ - { - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('can force overwrite of a file already in the compilation', (done) => { - runForce({ - existingAsset: 'directoryfile.txt', - expectedAssetContent: { - 'directoryfile.txt': 'new', - }, - patterns: [ - { - force: true, - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - it('adds the context directory to the watch list', (done) => { run({ patterns: [ @@ -1354,46 +1119,6 @@ describe('apply function', () => { .catch(done); }); - it('only include files that have changed', (done) => { - runChange({ - expectedAssetKeys: ['tempfile1.txt'], - newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), - patterns: [ - { - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('include all files if copyUnmodified is true', (done) => { - runChange({ - expectedAssetKeys: [ - '.dottedfile', - 'directoryfile.txt', - 'nested/deep-nested/deepnested.txt', - 'nested/nestedfile.txt', - 'tempfile1.txt', - 'tempfile2.txt', - ], - newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), - options: { - copyUnmodified: true, - }, - patterns: [ - { - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - it('can move multiple files to a non-root directory with name, hash and ext', (done) => { runEmit({ expectedAssetKeys: [ @@ -1413,21 +1138,6 @@ describe('apply function', () => { .catch(done); }); - it('can move multiple files to a non-root directory with [1]', (done) => { - runEmit({ - expectedAssetKeys: ['nested/txt'], - patterns: [ - { - from: 'directory/nested/deep-nested', - to: 'nested/[1]', - test: /\.([^.]*)$/, - }, - ], - }) - .then(done) - .catch(done); - }); - it("can move a directory's contents to the root directory from symbolic link", (done) => { runEmit({ // Windows doesn't support symbolic link @@ -1545,326 +1255,16 @@ describe('apply function', () => { }); }); - describe('modified files', () => { - it('copy only changed files', (done) => { - runChange({ - expectedAssetKeys: ['dest1/tempfile1.txt'], - newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), - patterns: [ - { - context: 'directory', - from: '**/*.txt', - to: 'dest1', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('copy only changed files (multiple patterns)', (done) => { - runChange({ - expectedAssetKeys: ['dest1/tempfile1.txt', 'dest2/tempfile1.txt'], - newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), - patterns: [ - { - context: 'directory', - from: '**/*.txt', - to: 'dest1', - }, - { - context: 'directory', - from: '**/*.txt', - to: 'dest2', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('copy only changed files (multiple patterns with difference context)', (done) => { - runChange({ - expectedAssetKeys: [ - 'dest1/tempfile1.txt', - 'dest2/directory/tempfile1.txt', - ], - newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt'), - patterns: [ - { - context: 'directory', - from: '**/*.txt', - to: 'dest1', - }, - { - from: '**/*.txt', - to: 'dest2', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('copy only changed files (multiple patterns with difference context 1)', (done) => { - runChange({ - expectedAssetKeys: [ - 'dest1/directory/tempfile1.txt', - 'dest2/tempfile1.txt', - ], - newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt'), - patterns: [ - { - from: '**/*.txt', - to: 'dest1', - }, - { - context: 'directory', - from: '**/*.txt', - to: 'dest2', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('copy only changed files (multiple patterns with difference context 2)', (done) => { - runChange({ - expectedAssetKeys: ['dest1/tempfile1.txt'], - newFileLoc1: path.join(HELPER_DIR, 'tempfile1.txt'), - newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), - patterns: [ - { - from: '**/*.txt', - to: 'dest1', - }, - { - context: 'directory', - from: '**/*.txt', - to: 'dest2', - }, - ], - }) - .then(done) - .catch(done); - }); - }); - - describe('options', () => { - describe('ignore', () => { - it('ignores files when from is a file', (done) => { - runEmit({ - expectedAssetKeys: ['directoryfile.txt'], - options: { - ignore: ['file.*'], - }, - patterns: [ - { - from: 'file.txt', - }, - { - from: 'directory/directoryfile.txt', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores files when from is a directory', (done) => { - runEmit({ - expectedAssetKeys: [ - '.dottedfile', - 'directoryfile.txt', - 'nested/deep-nested/deepnested.txt', - ], - options: { - ignore: ['*/nestedfile.*'], - }, - patterns: [ - { - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores files with a certain extension', (done) => { - runEmit({ - expectedAssetKeys: ['.dottedfile'], - options: { - ignore: ['*.txt'], - }, - patterns: [ - { - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores files that start with a dot', (done) => { - runEmit({ - expectedAssetKeys: [ - '[!]/hello.txt', - 'binextension.bin', - 'dir (86)/file.txt', - 'dir (86)/nesteddir/deepnesteddir/deepnesteddir.txt', - 'dir (86)/nesteddir/nestedfile.txt', - 'file.txt', - 'file.txt.gz', - 'directory/directoryfile.txt', - 'directory/nested/deep-nested/deepnested.txt', - 'directory/nested/nestedfile.txt', - '[special?directory]/directoryfile.txt', - '[special?directory]/(special-*file).txt', - '[special?directory]/nested/nestedfile.txt', - 'noextension', - ], - options: { - ignore: ['.dottedfile', '.file.txt'], - }, - patterns: [ - { - from: '.', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores all files except those with dots', (done) => { - runEmit({ - expectedAssetKeys: ['.file.txt', 'directory/.dottedfile'], - options: { - ignore: [ - { - dot: false, - glob: '**/*', - }, - ], - }, - patterns: [ - { - from: '.', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores all files even if they start with a dot', (done) => { - runEmit({ - expectedAssetKeys: [], - options: { - ignore: ['**/*'], - }, - patterns: [ - { - from: '.', - }, - ], - }) - .then(done) - .catch(done); - }); - - it('ignores nested directory', (done) => { - runEmit({ - expectedAssetKeys: [ - '.file.txt', - '[!]/hello.txt', - 'binextension.bin', - 'dir (86)/file.txt', - 'dir (86)/nesteddir/deepnesteddir/deepnesteddir.txt', - 'dir (86)/nesteddir/nestedfile.txt', - 'file.txt', - 'file.txt.gz', - 'noextension', - ], - options: { - ignore: [ - 'directory/**/*', - `[[]special${ - process.platform === 'win32' ? '' : '[?]' - }directory]/**/*`, - ], - }, - patterns: [ - { - from: '.', - }, - ], - }) - .then(done) - .catch(done); - }); - - if (path.sep === '/') { - it('ignores nested directory(can use "\\" to escape if path.sep is "/")', (done) => { - runEmit({ - expectedAssetKeys: [ - '.file.txt', - '[!]/hello.txt', - 'binextension.bin', - 'dir (86)/file.txt', - 'dir (86)/nesteddir/deepnesteddir/deepnesteddir.txt', - 'dir (86)/nesteddir/nestedfile.txt', - 'file.txt', - 'file.txt.gz', - 'noextension', - ], - options: { - ignore: ['directory/**/*', '\\[special\\?directory\\]/**/*'], - }, - patterns: [ - { - from: '.', - }, - ], - }) - .then(done) - .catch(done); - }); - } - - it('ignores nested directory (glob)', (done) => { - runEmit({ - expectedAssetKeys: ['.dottedfile', 'directoryfile.txt'], - options: { - ignore: ['nested/**/*'], - }, - patterns: [ - { - from: 'directory', - }, - ], - }) - .then(done) - .catch(done); - }); - }); - - describe('context', () => { - it('overrides webpack config context with absolute path', (done) => { - runEmit({ - expectedAssetKeys: [ - 'newdirectory/deep-nested/deepnested.txt', - 'newdirectory/nestedfile.txt', - ], - options: { - context: path.resolve(HELPER_DIR, 'directory'), + describe('options', () => { + describe('context', () => { + it('overrides webpack config context with absolute path', (done) => { + runEmit({ + expectedAssetKeys: [ + 'newdirectory/deep-nested/deepnested.txt', + 'newdirectory/nestedfile.txt', + ], + options: { + context: path.resolve(HELPER_DIR, 'directory'), }, patterns: [ { @@ -1939,244 +1339,6 @@ describe('apply function', () => { .catch(done); }); }); - - describe('cache', () => { - const cacheDir = findCacheDir({ name: 'copy-webpack-plugin' }); - - beforeEach(() => cacache.rm.all(cacheDir)); - - it('file should be cached', (done) => { - const newContent = 'newchanged!'; - const from = 'file.txt'; - - runEmit({ - expectedAssetKeys: ['file.txt'], - expectedAssetContent: { - 'file.txt': newContent, - }, - patterns: [ - { - from, - cache: true, - transform: function transform(content) { - return new Promise((resolve) => { - resolve(`${content}changed!`); - }); - }, - }, - ], - }) - .then(() => - cacache.ls(cacheDir).then((cacheEntries) => { - const cacheKeys = Object.keys(cacheEntries); - - expect(cacheKeys).toHaveLength(1); - - cacheKeys.forEach((cacheKey) => { - // eslint-disable-next-line no-new-func - const cacheEntry = new Function( - `'use strict'\nreturn ${cacheKey}` - )(); - - expect(cacheEntry.pattern.from).toBe(from); - }); - }) - ) - .then(done) - .catch(done); - }); - - it('files in directory should be cached', (done) => { - const from = 'directory'; - - runEmit({ - expectedAssetKeys: [ - '.dottedfile', - 'directoryfile.txt', - 'nested/deep-nested/deepnested.txt', - 'nested/nestedfile.txt', - ], - expectedAssetContent: { - '.dottedfile': 'dottedfile contents\nchanged!', - 'directoryfile.txt': 'newchanged!', - 'nested/nestedfile.txt': 'changed!', - }, - patterns: [ - { - from, - cache: true, - transform: function transform(content) { - return new Promise((resolve) => { - resolve(`${content}changed!`); - }); - }, - }, - ], - }) - .then(() => - cacache.ls(cacheDir).then((cacheEntries) => { - const cacheKeys = Object.keys(cacheEntries); - - expect(cacheKeys).toHaveLength(3); - - cacheKeys.forEach((cacheKey) => { - // eslint-disable-next-line no-new-func - const cacheEntry = new Function( - `'use strict'\nreturn ${cacheKey}` - )(); - - expect(cacheEntry.pattern.from).toBe(from); - }); - }) - ) - .then(done) - .catch(done); - }); - - it('glob should be cached', (done) => { - const from = '*.txt'; - - runEmit({ - expectedAssetKeys: ['file.txt'], - expectedAssetContent: { - 'file.txt': 'newchanged!', - }, - patterns: [ - { - from, - cache: true, - transform: function transform(content) { - return new Promise((resolve) => { - resolve(`${content}changed!`); - }); - }, - }, - ], - }) - .then(() => - cacache.ls(cacheDir).then((cacheEntries) => { - const cacheKeys = Object.keys(cacheEntries); - - expect(cacheKeys).toHaveLength(1); - - cacheKeys.forEach((cacheKey) => { - // eslint-disable-next-line no-new-func - const cacheEntry = new Function( - `'use strict'\nreturn ${cacheKey}` - )(); - - expect(cacheEntry.pattern.from).toBe(from); - }); - }) - ) - .then(done) - .catch(done); - }); - - it('file should be cached with custom cache key', (done) => { - const newContent = 'newchanged!'; - const from = 'file.txt'; - - runEmit({ - expectedAssetKeys: ['file.txt'], - expectedAssetContent: { - 'file.txt': newContent, - }, - patterns: [ - { - from, - cache: { - key: 'foobar', - }, - transform(content) { - return new Promise((resolve) => { - resolve(`${content}changed!`); - }); - }, - }, - ], - }) - .then(() => - cacache.ls(cacheDir).then((cacheEntries) => { - const cacheKeys = Object.keys(cacheEntries); - - expect(cacheKeys).toHaveLength(1); - - cacheKeys.forEach((cacheKey) => { - expect(cacheKey).toBe('foobar'); - }); - }) - ) - .then(done) - .catch(done); - }); - - it('binary file should be cached', (done) => { - const from = 'file.txt.gz'; - const content = fs.readFileSync(path.join(HELPER_DIR, from)); - const expectedNewContent = zlib.gzipSync('newchanged!'); - - expect(isGzip(content)).toBe(true); - expect(isGzip(expectedNewContent)).toBe(true); - - runEmit({ - expectedAssetKeys: ['file.txt.gz'], - expectedAssetContent: { - 'file.txt.gz': expectedNewContent, - }, - patterns: [ - { - from, - cache: true, - // eslint-disable-next-line no-shadow - transform: function transform(content) { - expect(isGzip(content)).toBe(true); - - return new Promise((resolve) => { - // eslint-disable-next-line no-shadow - zlib.unzip(content, (error, content) => { - if (error) { - throw error; - } - - const newContent = Buffer.from(`${content}changed!`); - - // eslint-disable-next-line no-shadow - zlib.gzip(newContent, (error, compressedData) => { - if (error) { - throw error; - } - - expect(isGzip(compressedData)).toBe(true); - - return resolve(compressedData); - }); - }); - }); - }, - }, - ], - }) - .then(() => - cacache.ls(cacheDir).then((cacheEntries) => { - const cacheKeys = Object.keys(cacheEntries); - - expect(cacheKeys).toHaveLength(1); - - cacheKeys.forEach((cacheKey) => { - // eslint-disable-next-line no-new-func - const cacheEntry = new Function( - `'use strict'\nreturn ${cacheKey}` - )(); - - expect(cacheEntry.pattern.from).toBe(from); - }); - }) - ) - .then(done) - .catch(done); - }); - }); }); it('should move a file and use posix separator for emitting assets', (done) => { @@ -2193,4 +1355,172 @@ describe('apply function', () => { .then(done) .catch(done); }); + + describe('watch mode', () => { + it('only include files that have changed', (done) => { + runChange({ + expectedAssetKeys: ['tempfile1.txt'], + newFileLoc1: path.join(HELPER_DIR, 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt'), + patterns: [ + { + from: 'tempfile1.txt', + }, + { + from: 'tempfile2.txt', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('only include files that have changed', (done) => { + runChange({ + expectedAssetKeys: ['tempfile1.txt'], + newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), + patterns: [ + { + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('include all files if copyUnmodified is true', (done) => { + runChange({ + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + 'tempfile1.txt', + 'tempfile2.txt', + ], + newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), + options: { + copyUnmodified: true, + }, + patterns: [ + { + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('copy only changed files', (done) => { + runChange({ + expectedAssetKeys: ['dest1/tempfile1.txt'], + newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), + patterns: [ + { + context: 'directory', + from: '**/*.txt', + to: 'dest1', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('copy only changed files (multiple patterns)', (done) => { + runChange({ + expectedAssetKeys: ['dest1/tempfile1.txt', 'dest2/tempfile1.txt'], + newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), + patterns: [ + { + context: 'directory', + from: '**/*.txt', + to: 'dest1', + }, + { + context: 'directory', + from: '**/*.txt', + to: 'dest2', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('copy only changed files (multiple patterns with difference context)', (done) => { + runChange({ + expectedAssetKeys: [ + 'dest1/tempfile1.txt', + 'dest2/directory/tempfile1.txt', + ], + newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt'), + patterns: [ + { + context: 'directory', + from: '**/*.txt', + to: 'dest1', + }, + { + from: '**/*.txt', + to: 'dest2', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('copy only changed files (multiple patterns with difference context 1)', (done) => { + runChange({ + expectedAssetKeys: [ + 'dest1/directory/tempfile1.txt', + 'dest2/tempfile1.txt', + ], + newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt'), + patterns: [ + { + from: '**/*.txt', + to: 'dest1', + }, + { + context: 'directory', + from: '**/*.txt', + to: 'dest2', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('copy only changed files (multiple patterns with difference context 2)', (done) => { + runChange({ + expectedAssetKeys: ['dest1/tempfile1.txt'], + newFileLoc1: path.join(HELPER_DIR, 'tempfile1.txt'), + newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt'), + patterns: [ + { + from: '**/*.txt', + to: 'dest1', + }, + { + context: 'directory', + from: '**/*.txt', + to: 'dest2', + }, + ], + }) + .then(done) + .catch(done); + }); + }); }); diff --git a/test/cache-option.test.js b/test/cache-option.test.js new file mode 100644 index 00000000..bebbdd49 --- /dev/null +++ b/test/cache-option.test.js @@ -0,0 +1,249 @@ +import fs from 'fs'; +import path from 'path'; +import zlib from 'zlib'; + +import cacache from 'cacache'; +import findCacheDir from 'find-cache-dir'; +import isGzip from 'is-gzip'; + +import { runEmit } from './utils/run'; + +const HELPER_DIR = path.join(__dirname, 'helpers'); + +describe('cache option', () => { + const cacheDir = findCacheDir({ name: 'copy-webpack-plugin' }); + + beforeEach(() => cacache.rm.all(cacheDir)); + + it('should cache when "from" is a file', (done) => { + const newContent = 'newchanged!'; + const from = 'file.txt'; + + runEmit({ + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': newContent, + }, + patterns: [ + { + from, + cache: true, + transform: function transform(content) { + return new Promise((resolve) => { + resolve(`${content}changed!`); + }); + }, + }, + ], + }) + .then(() => + cacache.ls(cacheDir).then((cacheEntries) => { + const cacheKeys = Object.keys(cacheEntries); + + expect(cacheKeys).toHaveLength(1); + + cacheKeys.forEach((cacheKey) => { + // eslint-disable-next-line no-new-func + const cacheEntry = new Function( + `'use strict'\nreturn ${cacheKey}` + )(); + + expect(cacheEntry.pattern.from).toBe(from); + }); + }) + ) + .then(done) + .catch(done); + }); + + it('should cache files when "from" is a directory', (done) => { + const from = 'directory'; + + runEmit({ + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetContent: { + '.dottedfile': 'dottedfile contents\nchanged!', + 'directoryfile.txt': 'newchanged!', + 'nested/nestedfile.txt': 'changed!', + }, + patterns: [ + { + from, + cache: true, + transform: function transform(content) { + return new Promise((resolve) => { + resolve(`${content}changed!`); + }); + }, + }, + ], + }) + .then(() => + cacache.ls(cacheDir).then((cacheEntries) => { + const cacheKeys = Object.keys(cacheEntries); + + expect(cacheKeys).toHaveLength(3); + + cacheKeys.forEach((cacheKey) => { + // eslint-disable-next-line no-new-func + const cacheEntry = new Function( + `'use strict'\nreturn ${cacheKey}` + )(); + + expect(cacheEntry.pattern.from).toBe(from); + }); + }) + ) + .then(done) + .catch(done); + }); + + it('should cache when "from" is a glob', (done) => { + const from = 'directory/*.txt'; + + runEmit({ + expectedAssetKeys: ['directory/directoryfile.txt'], + expectedAssetContent: { + 'directory/directoryfile.txt': 'newchanged!', + }, + patterns: [ + { + from, + cache: true, + transform: function transform(content) { + return new Promise((resolve) => { + resolve(`${content}changed!`); + }); + }, + }, + ], + }) + .then(() => + cacache.ls(cacheDir).then((cacheEntries) => { + const cacheKeys = Object.keys(cacheEntries); + + expect(cacheKeys).toHaveLength(1); + + cacheKeys.forEach((cacheKey) => { + // eslint-disable-next-line no-new-func + const cacheEntry = new Function( + `'use strict'\nreturn ${cacheKey}` + )(); + + expect(cacheEntry.pattern.from).toBe(from); + }); + }) + ) + .then(done) + .catch(done); + }); + + it('should cache file with custom cache key', (done) => { + const newContent = 'newchanged!'; + const from = 'file.txt'; + + runEmit({ + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': newContent, + }, + patterns: [ + { + from, + cache: { + key: 'foobar', + }, + transform(content) { + return new Promise((resolve) => { + resolve(`${content}changed!`); + }); + }, + }, + ], + }) + .then(() => + cacache.ls(cacheDir).then((cacheEntries) => { + const cacheKeys = Object.keys(cacheEntries); + + expect(cacheKeys).toHaveLength(1); + + cacheKeys.forEach((cacheKey) => { + expect(cacheKey).toBe('foobar'); + }); + }) + ) + .then(done) + .catch(done); + }); + + it('should cache binary file', (done) => { + const from = 'file.txt.gz'; + const content = fs.readFileSync(path.join(HELPER_DIR, from)); + const expectedNewContent = zlib.gzipSync('newchanged!'); + + expect(isGzip(content)).toBe(true); + expect(isGzip(expectedNewContent)).toBe(true); + + runEmit({ + expectedAssetKeys: ['file.txt.gz'], + expectedAssetContent: { + 'file.txt.gz': expectedNewContent, + }, + patterns: [ + { + from, + cache: true, + // eslint-disable-next-line no-shadow + transform: function transform(content) { + expect(isGzip(content)).toBe(true); + + return new Promise((resolve) => { + // eslint-disable-next-line no-shadow + zlib.unzip(content, (error, content) => { + if (error) { + throw error; + } + + const newContent = Buffer.from(`${content}changed!`); + + // eslint-disable-next-line no-shadow + zlib.gzip(newContent, (error, compressedData) => { + if (error) { + throw error; + } + + expect(isGzip(compressedData)).toBe(true); + + return resolve(compressedData); + }); + }); + }); + }, + }, + ], + }) + .then(() => + cacache.ls(cacheDir).then((cacheEntries) => { + const cacheKeys = Object.keys(cacheEntries); + + expect(cacheKeys).toHaveLength(1); + + cacheKeys.forEach((cacheKey) => { + // eslint-disable-next-line no-new-func + const cacheEntry = new Function( + `'use strict'\nreturn ${cacheKey}` + )(); + + expect(cacheEntry.pattern.from).toBe(from); + }); + }) + ) + .then(done) + .catch(done); + }); +}); diff --git a/test/flatten-option.test.js b/test/flatten-option.test.js new file mode 100644 index 00000000..80766edb --- /dev/null +++ b/test/flatten-option.test.js @@ -0,0 +1,147 @@ +import { runEmit } from './utils/run'; + +describe('flatten option', () => { + it('should flatten a directory\'s files to a root directory when "from" is a file', (done) => { + runEmit({ + expectedAssetKeys: ['directoryfile.txt'], + patterns: [ + { + flatten: true, + from: 'directory/directoryfile.txt', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten a directory\'s files to a new directory when "from" is a file', (done) => { + runEmit({ + expectedAssetKeys: ['nested/directoryfile.txt'], + patterns: [ + { + flatten: true, + from: 'directory/directoryfile.txt', + to: 'nested', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten a directory\'s files to a root directory when "from" is a directory', (done) => { + runEmit({ + expectedAssetKeys: [ + '.dottedfile', + 'deepnested.txt', + 'directoryfile.txt', + 'nestedfile.txt', + ], + patterns: [ + { + flatten: true, + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten a directory\'s files to new directory when "from" is a directory', (done) => { + runEmit({ + expectedAssetKeys: [ + 'newdirectory/.dottedfile', + 'newdirectory/deepnested.txt', + 'newdirectory/directoryfile.txt', + 'newdirectory/nestedfile.txt', + ], + patterns: [ + { + flatten: true, + from: 'directory', + to: 'newdirectory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten a directory\'s files to a root directory when "from" is a glob', (done) => { + runEmit({ + expectedAssetKeys: [ + 'deepnested.txt', + 'directoryfile.txt', + 'nestedfile.txt', + ], + patterns: [ + { + flatten: true, + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten a directory\'s files to a new directory when "from" is a glob', (done) => { + runEmit({ + expectedAssetKeys: [ + 'nested/deepnested.txt', + 'nested/directoryfile.txt', + 'nested/nestedfile.txt', + ], + patterns: [ + { + flatten: true, + from: 'directory/**/*', + to: 'nested', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten files in a relative context to a root directory when "from" is a glob', (done) => { + runEmit({ + expectedAssetKeys: [ + 'deepnested.txt', + 'directoryfile.txt', + 'nestedfile.txt', + ], + patterns: [ + { + context: 'directory', + flatten: true, + from: '**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should flatten files in a relative context to a non-root directory when "from" is a glob', (done) => { + runEmit({ + expectedAssetKeys: [ + 'nested/deepnested.txt', + 'nested/directoryfile.txt', + 'nested/nestedfile.txt', + ], + patterns: [ + { + context: 'directory', + flatten: true, + from: '**/*', + to: 'nested', + }, + ], + }) + .then(done) + .catch(done); + }); +}); diff --git a/test/force-option.test.js b/test/force-option.test.js new file mode 100644 index 00000000..1567007d --- /dev/null +++ b/test/force-option.test.js @@ -0,0 +1,237 @@ +import { runForce } from './utils/run'; + +describe('force option', () => { + describe('is not specified', () => { + it('should not overwrite a file already in the compilation by default when "from" is a file', (done) => { + runForce({ + existingAssets: ['file.txt'], + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': 'existing', + }, + patterns: [ + { + from: 'file.txt', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should not overwrite files already in the compilation when "from" is a directory', (done) => { + runForce({ + existingAssets: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetContent: { + '.dottedfile': 'existing', + 'nested/deep-nested/deepnested.txt': 'existing', + 'nested/nestedfile.txt': 'existing', + 'directoryfile.txt': 'existing', + }, + patterns: [ + { + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should not overwrite files already in the compilation when "from" is a glob', (done) => { + runForce({ + existingAssets: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetKeys: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetContent: { + 'directory/nested/deep-nested/deepnested.txt': 'existing', + 'directory/nested/nestedfile.txt': 'existing', + 'directory/directoryfile.txt': 'existing', + }, + patterns: [ + { + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + }); + + describe('is "false" (Boolean)', () => { + it('should not overwrite a file already in the compilation by default when "from" is a file', (done) => { + runForce({ + existingAssets: ['file.txt'], + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': 'existing', + }, + patterns: [ + { + force: false, + from: 'file.txt', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should not overwrite files already in the compilation when "from" is a directory', (done) => { + runForce({ + existingAssets: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetContent: { + '.dottedfile': 'existing', + 'nested/deep-nested/deepnested.txt': 'existing', + 'nested/nestedfile.txt': 'existing', + 'directoryfile.txt': 'existing', + }, + patterns: [ + { + force: false, + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should not overwrite files already in the compilation when "from" is a glob', (done) => { + runForce({ + existingAssets: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetKeys: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetContent: { + 'directory/nested/deep-nested/deepnested.txt': 'existing', + 'directory/nested/nestedfile.txt': 'existing', + 'directory/directoryfile.txt': 'existing', + }, + patterns: [ + { + force: false, + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + }); + + describe('is "true" (Boolean)', () => { + it('should force overwrite a file already in the compilation when "from" is a file', (done) => { + runForce({ + existingAssets: ['file.txt'], + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': 'new', + }, + patterns: [ + { + force: true, + from: 'file.txt', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should force overwrite files already in the compilation when "from" is a directory', (done) => { + runForce({ + existingAssets: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetContent: { + '.dottedfile': 'dottedfile contents\n', + 'nested/deep-nested/deepnested.txt': '', + 'nested/nestedfile.txt': '', + 'directoryfile.txt': 'new', + }, + patterns: [ + { + force: true, + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should force overwrite files already in the compilation when "from" is a glob', (done) => { + runForce({ + existingAssets: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetKeys: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetContent: { + 'directory/nested/deep-nested/deepnested.txt': '', + 'directory/nested/nestedfile.txt': '', + 'directory/directoryfile.txt': 'new', + }, + patterns: [ + { + force: true, + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + }); +}); diff --git a/test/ignore-option.test.js b/test/ignore-option.test.js new file mode 100644 index 00000000..50db76c8 --- /dev/null +++ b/test/ignore-option.test.js @@ -0,0 +1,186 @@ +import { runEmit } from './utils/run'; + +describe('ignore option', () => { + it('should ignore files when "from" is a file', (done) => { + runEmit({ + expectedAssetKeys: [], + patterns: [ + { + ignore: ['file.*'], + from: 'file.txt', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should files when "from" is a directory', (done) => { + runEmit({ + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + ], + patterns: [ + { + ignore: ['*/nestedfile.*'], + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should files in nested directory when "from" is a directory', (done) => { + runEmit({ + expectedAssetKeys: ['.dottedfile', 'directoryfile.txt'], + patterns: [ + { + ignore: ['**/nested/**'], + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should files when from is a glob', (done) => { + runEmit({ + expectedAssetKeys: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + ], + patterns: [ + { + ignore: ['*nestedfile.*'], + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should files in nested directory when from is a glob', (done) => { + runEmit({ + expectedAssetKeys: ['directory/directoryfile.txt'], + patterns: [ + { + ignore: ['*/nested/**'], + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should ignore files with a certain extension', (done) => { + runEmit({ + expectedAssetKeys: ['.dottedfile'], + patterns: [ + { + ignore: ['*.txt'], + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should ignore files with multiple ignore patterns', (done) => { + runEmit({ + expectedAssetKeys: ['directory/nested/nestedfile.txt'], + patterns: [ + { + ignore: ['directoryfile.*', '**/deep-nested/**'], + from: 'directory/**/*', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should ignore files except those with dots', (done) => { + runEmit({ + expectedAssetKeys: ['.dottedfile'], + options: { + ignore: [ + { + dot: false, + glob: '**/*', + }, + ], + }, + patterns: [ + { + from: 'directory', + ignore: [ + { + dot: false, + glob: '**/*', + }, + ], + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should ignore files that start with a dot', (done) => { + runEmit({ + expectedAssetKeys: [ + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + patterns: [ + { + ignore: ['.dottedfile'], + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should ignores all files even if they start with a dot', (done) => { + runEmit({ + expectedAssetKeys: [], + options: { + ignore: ['**/*'], + }, + patterns: [ + { + from: 'directory', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should ignore files when "from" is a file (global ignore)', (done) => { + runEmit({ + expectedAssetKeys: [], + options: { + ignore: ['file.*'], + }, + patterns: [ + { + ignore: ['file.*'], + from: 'file.txt', + }, + ], + }) + .then(done) + .catch(done); + }); +}); diff --git a/test/test-option.test.js b/test/test-option.test.js new file mode 100644 index 00000000..c0503161 --- /dev/null +++ b/test/test-option.test.js @@ -0,0 +1,73 @@ +import path from 'path'; + +import { runEmit } from './utils/run'; + +describe('test option', () => { + it('should move files to a root directory with [1]', (done) => { + runEmit({ + expectedAssetKeys: ['txt'], + patterns: [ + { + from: 'directory/nested/deep-nested', + to: '[1]', + test: /\.([^.]*)$/, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should move files to a non-root directory with [1]', (done) => { + runEmit({ + expectedAssetKeys: ['nested/txt'], + patterns: [ + { + from: 'directory/nested/deep-nested', + to: 'nested/[1]', + test: /\.([^.]*)$/, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should move files and flatten them to a non-root directory with [1]-[2].[ext]', (done) => { + runEmit({ + expectedAssetKeys: [ + 'nested/deep-nested-deepnested.txt', + 'nested/directory-directoryfile.txt', + 'nested/nested-nestedfile.txt', + ], + patterns: [ + { + from: 'directory/**/*', + test: `([^\\${path.sep}]+)\\${path.sep}([^\\${path.sep}]+)\\.\\w+$`, + to: 'nested/[1]-[2].[ext]', + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should move files and flatten them to a root directory with [1]-[2].[ext]', (done) => { + runEmit({ + expectedAssetKeys: [ + 'deep-nested-deepnested.txt', + 'directory-directoryfile.txt', + 'nested-nestedfile.txt', + ], + patterns: [ + { + from: 'directory/**/*', + test: `([^\\${path.sep}]+)\\${path.sep}([^\\${path.sep}]+)\\.\\w+$`, + to: '[1]-[2].[ext]', + }, + ], + }) + .then(done) + .catch(done); + }); +}); diff --git a/test/transform-option.test.js b/test/transform-option.test.js new file mode 100644 index 00000000..f1434b91 --- /dev/null +++ b/test/transform-option.test.js @@ -0,0 +1,184 @@ +import path from 'path'; + +import { runEmit } from './utils/run'; + +const HELPER_DIR = path.join(__dirname, 'helpers'); + +describe('transform option', () => { + it('should transform file when "from" is a file', (done) => { + runEmit({ + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': 'newchanged', + }, + patterns: [ + { + from: 'file.txt', + transform(content, absoluteFrom) { + expect(absoluteFrom.includes(HELPER_DIR)).toBe(true); + + return `${content}changed`; + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should transform target path of every when "from" is a directory', (done) => { + runEmit({ + expectedAssetKeys: [ + '.dottedfile', + 'directoryfile.txt', + 'nested/deep-nested/deepnested.txt', + 'nested/nestedfile.txt', + ], + expectedAssetContent: { + '.dottedfile': 'dottedfile contents\nchanged', + 'directoryfile.txt': 'newchanged', + 'nested/deep-nested/deepnested.txt': 'changed', + 'nested/nestedfile.txt': 'changed', + }, + patterns: [ + { + from: 'directory', + transform(content, absoluteFrom) { + expect(absoluteFrom.includes(HELPER_DIR)).toBe(true); + + return `${content}changed`; + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should transform target path of every file when "from" is a glob', (done) => { + runEmit({ + expectedAssetKeys: [ + 'directory/directoryfile.txt', + 'directory/nested/deep-nested/deepnested.txt', + 'directory/nested/nestedfile.txt', + ], + expectedAssetContent: { + 'directory/directoryfile.txt': 'newchanged', + 'directory/nested/deep-nested/deepnested.txt': 'changed', + 'directory/nested/nestedfile.txt': 'changed', + }, + patterns: [ + { + from: 'directory/**/*', + transform(content, absoluteFrom) { + expect(absoluteFrom.includes(HELPER_DIR)).toBe(true); + + return `${content}changed`; + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should transform file when function return Promise', (done) => { + runEmit({ + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': 'newchanged!', + }, + patterns: [ + { + from: 'file.txt', + transform(content) { + return new Promise((resolve) => { + resolve(`${content}changed!`); + }); + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should transform target path when async function used', (done) => { + runEmit({ + expectedAssetKeys: ['file.txt'], + expectedAssetContent: { + 'file.txt': 'newchanged!', + }, + patterns: [ + { + from: 'file.txt', + async transform(content) { + const newPath = await new Promise((resolve) => { + resolve(`${content}changed!`); + }); + + return newPath; + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should warns when function throw error', (done) => { + runEmit({ + expectedAssetKeys: [], + expectedErrors: [new Error('a failure happened')], + patterns: [ + { + from: 'file.txt', + transform() { + // eslint-disable-next-line no-throw-literal + throw new Error('a failure happened'); + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should warns when Promise was rejected', (done) => { + runEmit({ + expectedAssetKeys: [], + expectedErrors: [new Error('a failure happened')], + patterns: [ + { + from: 'file.txt', + transform() { + return new Promise((resolve, reject) => { + return reject(new Error('a failure happened')); + }); + }, + }, + ], + }) + .then(done) + .catch(done); + }); + + it('should warns when async function throw error', (done) => { + runEmit({ + expectedAssetKeys: [], + expectedErrors: [new Error('a failure happened')], + patterns: [ + { + from: 'file.txt', + async transform() { + await new Promise((resolve, reject) => { + reject(new Error('a failure happened')); + }); + }, + }, + ], + }) + .then(done) + .catch(done); + }); +}); diff --git a/test/transformPath-option.test.js b/test/transformPath-option.test.js index 3ab1b161..ee066238 100644 --- a/test/transformPath-option.test.js +++ b/test/transformPath-option.test.js @@ -51,20 +51,13 @@ describe('transformPath option', () => { it('should transform target path of every file when "from" is a glob', (done) => { runEmit({ expectedAssetKeys: [ - '/some/path/(special-*file).txt.tst', - '/some/path/binextension.bin.tst', '/some/path/deepnested.txt.tst', - '/some/path/deepnesteddir.txt.tst', - '/some/path/file.txt.tst', - '/some/path/file.txt.gz.tst', '/some/path/directoryfile.txt.tst', '/some/path/nestedfile.txt.tst', - '/some/path/noextension.tst', - '/some/path/hello.txt.tst', ], patterns: [ { - from: '**/*', + from: 'directory/**/*', transformPath(targetPath, absoluteFrom) { expect(absoluteFrom.includes(HELPER_DIR)).toBe(true); @@ -177,24 +170,13 @@ describe('transformPath option', () => { it('should transform target path of every file in glob after applying template', (done) => { runEmit({ expectedAssetKeys: [ - 'transformed/[!]/hello-d41d8c.txt', - 'transformed/[special?directory]/directoryfile-22af64.txt', - 'transformed/[special?directory]/(special-*file)-0bd650.txt', - 'transformed/[special?directory]/nested/nestedfile-d41d8c.txt', - 'transformed/binextension-d41d8c.bin', - 'transformed/dir (86)/file-d41d8c.txt', - 'transformed/dir (86)/nesteddir/deepnesteddir/deepnesteddir-d41d8c.txt', - 'transformed/dir (86)/nesteddir/nestedfile-d41d8c.txt', - 'transformed/file-22af64.txt', - 'transformed/file.txt-5b311c.gz', 'transformed/directory/directoryfile-22af64.txt', 'transformed/directory/nested/deep-nested/deepnested-d41d8c.txt', 'transformed/directory/nested/nestedfile-d41d8c.txt', - 'transformed/noextension-d41d8c', ], patterns: [ { - from: '**/*', + from: 'directory/**/*', to: 'nested/[path][name]-[hash:6].[ext]', transformPath(targetPath, absoluteFrom) { expect(absoluteFrom.includes(HELPER_DIR)).toBe(true); diff --git a/test/utils/run.js b/test/utils/run.js index 17cf14f1..d9f5b68c 100644 --- a/test/utils/run.js +++ b/test/utils/run.js @@ -136,14 +136,17 @@ function runForce(opts) { opts.compilation = { assets: {}, }; - // eslint-disable-next-line no-param-reassign - opts.compilation.assets[opts.existingAsset] = { - source() { - return 'existing'; - }, - }; - return run(opts).then(() => {}); + opts.existingAssets.forEach((assetName) => { + // eslint-disable-next-line no-param-reassign + opts.compilation.assets[assetName] = { + source() { + return 'existing'; + }, + }; + }); + + return runEmit(opts).then(() => {}); } function runChange(opts) {