From eb759a44fdad1f158ff315f653ade89dafa843ef Mon Sep 17 00:00:00 2001 From: sainthkh Date: Mon, 4 Feb 2019 02:28:22 +0900 Subject: [PATCH] Improve tests: symlink tests, Kotlin tests, and maybe test-util module (#2605) * Ignore Kotlin tests and show messages when Java is not installed or configured. (#2603) * Skip symlink tests and show warning message when tests are run without admin privilege. (#2602) * Moved parcel-bundler/test/utils.js and integration-tests/test/utils.js into test-utils/src/utils.js. (#2604) * Fixed eslint errors. * Use the test to assert this.child.killed rather than checking time difference. (#2609) (#2612) --- .../core/integration-tests/test/bundler.js | 7 +- .../integration-tests/test/contentHashing.js | 2 +- packages/core/integration-tests/test/css.js | 8 +- packages/core/integration-tests/test/elm.js | 2 +- .../core/integration-tests/test/encodedURI.js | 2 +- packages/core/integration-tests/test/fs.js | 2 +- packages/core/integration-tests/test/glob.js | 2 +- packages/core/integration-tests/test/glsl.js | 7 +- .../core/integration-tests/test/graphql.js | 2 +- packages/core/integration-tests/test/hmr.js | 2 +- packages/core/integration-tests/test/html.js | 2 +- .../core/integration-tests/test/javascript.js | 36 ++- .../core/integration-tests/test/kotlin.js | 11 +- packages/core/integration-tests/test/less.js | 2 +- .../core/integration-tests/test/parser.js | 2 +- packages/core/integration-tests/test/pug.js | 2 +- .../core/integration-tests/test/reason.js | 2 +- packages/core/integration-tests/test/rust.js | 2 +- packages/core/integration-tests/test/sass.js | 2 +- .../integration-tests/test/schema-jsonld.js | 2 +- .../integration-tests/test/scope-hoisting.js | 2 +- .../core/integration-tests/test/server.js | 2 +- .../core/integration-tests/test/sourcemaps.js | 2 +- .../core/integration-tests/test/stylus.js | 2 +- .../core/integration-tests/test/sugarss.js | 2 +- .../core/integration-tests/test/typescript.js | 2 +- packages/core/integration-tests/test/utils.js | 280 +---------------- packages/core/integration-tests/test/vue.js | 2 +- packages/core/integration-tests/test/wasm.js | 2 +- .../core/integration-tests/test/watcher.js | 58 ++-- packages/core/parcel-bundler/test/asset.js | 2 +- .../core/parcel-bundler/test/autoinstall.js | 2 +- packages/core/parcel-bundler/test/fs-cache.js | 2 +- .../test/generateCertificate.js | 2 +- packages/core/parcel-bundler/test/plugins.js | 2 +- packages/core/parcel-bundler/test/resolver.js | 50 ++- packages/core/parcel-bundler/test/utils.js | 280 +---------------- packages/core/test-utils/src/utils.js | 292 ++++++++++++++++++ 38 files changed, 440 insertions(+), 645 deletions(-) diff --git a/packages/core/integration-tests/test/bundler.js b/packages/core/integration-tests/test/bundler.js index 7534f3a5603..3203dcca046 100644 --- a/packages/core/integration-tests/test/bundler.js +++ b/packages/core/integration-tests/test/bundler.js @@ -1,7 +1,12 @@ const assert = require('assert'); const sinon = require('sinon'); const path = require('path'); -const {assertBundleTree, bundle, bundler, nextBundle} = require('./utils'); +const { + assertBundleTree, + bundle, + bundler, + nextBundle +} = require('@parcel/test-utils'); describe('bundler', function() { it('should bundle once before exporting middleware', async function() { diff --git a/packages/core/integration-tests/test/contentHashing.js b/packages/core/integration-tests/test/contentHashing.js index 9dc279db394..584677c07c9 100644 --- a/packages/core/integration-tests/test/contentHashing.js +++ b/packages/core/integration-tests/test/contentHashing.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, rimraf, ncp} = require('./utils'); +const {bundle, rimraf, ncp} = require('@parcel/test-utils'); describe('content hashing', function() { beforeEach(async function() { diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index c022343cac8..422b8b9a01f 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -1,7 +1,13 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, run, assertBundleTree, rimraf, ncp} = require('./utils'); +const { + bundle, + run, + assertBundleTree, + rimraf, + ncp +} = require('@parcel/test-utils'); describe('css', function() { it('should produce two bundles when importing a CSS file', async function() { diff --git a/packages/core/integration-tests/test/elm.js b/packages/core/integration-tests/test/elm.js index 4ab71a716db..972c5a3a4a0 100644 --- a/packages/core/integration-tests/test/elm.js +++ b/packages/core/integration-tests/test/elm.js @@ -1,6 +1,6 @@ const assert = require('assert'); const fs = require('@parcel/fs'); -const {bundle, assertBundleTree, run} = require('./utils'); +const {bundle, assertBundleTree, run} = require('@parcel/test-utils'); describe('elm', function() { it('should produce a basic Elm bundle', async function() { diff --git a/packages/core/integration-tests/test/encodedURI.js b/packages/core/integration-tests/test/encodedURI.js index 8450f167962..4aecc42eff2 100644 --- a/packages/core/integration-tests/test/encodedURI.js +++ b/packages/core/integration-tests/test/encodedURI.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, assertBundleTree} = require('./utils'); +const {bundle, assertBundleTree} = require('@parcel/test-utils'); describe('encodedURI', function() { it('should support bundling files which names in encoded URI', async function() { diff --git a/packages/core/integration-tests/test/fs.js b/packages/core/integration-tests/test/fs.js index 1bfa96c2721..f466d80218f 100644 --- a/packages/core/integration-tests/test/fs.js +++ b/packages/core/integration-tests/test/fs.js @@ -1,7 +1,7 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('fs', function() { describe('--target=browser', function() { diff --git a/packages/core/integration-tests/test/glob.js b/packages/core/integration-tests/test/glob.js index 9663d7be4b6..7a7253408c9 100644 --- a/packages/core/integration-tests/test/glob.js +++ b/packages/core/integration-tests/test/glob.js @@ -1,7 +1,7 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('glob', function() { it('should require a glob of files', async function() { diff --git a/packages/core/integration-tests/test/glsl.js b/packages/core/integration-tests/test/glsl.js index b8b1db9e3db..e16f033f638 100644 --- a/packages/core/integration-tests/test/glsl.js +++ b/packages/core/integration-tests/test/glsl.js @@ -1,7 +1,12 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, run, assertBundleTree, normaliseNewlines} = require('./utils'); +const { + bundle, + run, + assertBundleTree, + normaliseNewlines +} = require('@parcel/test-utils'); describe('glsl', function() { it('should support requiring GLSL files via glslify', async function() { diff --git a/packages/core/integration-tests/test/graphql.js b/packages/core/integration-tests/test/graphql.js index 4c890f7b1dc..2a90d4b22ba 100644 --- a/packages/core/integration-tests/test/graphql.js +++ b/packages/core/integration-tests/test/graphql.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const gql = require('graphql-tag'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('graphql', function() { it('should support requiring graphql files', async function() { diff --git a/packages/core/integration-tests/test/hmr.js b/packages/core/integration-tests/test/hmr.js index 7ea84ce743b..6e5a91ce2ee 100644 --- a/packages/core/integration-tests/test/hmr.js +++ b/packages/core/integration-tests/test/hmr.js @@ -1,7 +1,7 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); -const {bundler, run, rimraf, ncp} = require('./utils'); +const {bundler, run, rimraf, ncp} = require('@parcel/test-utils'); const {sleep} = require('@parcel/test-utils'); const WebSocket = require('ws'); const json5 = require('json5'); diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index c498e84fc41..7b3ee6da5cf 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -1,6 +1,6 @@ const assert = require('assert'); const fs = require('@parcel/fs'); -const {bundle, assertBundleTree} = require('./utils'); +const {bundle, assertBundleTree} = require('@parcel/test-utils'); const path = require('path'); describe('html', function() { diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index ba255be5792..55286f20bea 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -8,8 +8,9 @@ const { assertBundleTree, deferred, ncp -} = require('./utils'); +} = require('@parcel/test-utils'); const {mkdirp} = require('@parcel/fs'); +const {symlinkPrivilegeWarning} = require('@parcel/test-utils'); const {symlinkSync} = require('fs'); describe('javascript', function() { @@ -1290,21 +1291,28 @@ describe('javascript', function() { inputDir ); - // Create the symlink here to prevent cross platform and git issues - symlinkSync( - path.join(inputDir, 'packages/foo'), - path.join(inputDir, 'node_modules/foo'), - 'dir' - ); + try { + // Create the symlink here to prevent cross platform and git issues + symlinkSync( + path.join(inputDir, 'packages/foo'), + path.join(inputDir, 'node_modules/foo'), + 'dir' + ); - await bundle(inputDir + '/index.js'); + await bundle(inputDir + '/index.js'); - let file = await fs.readFile( - path.join(__dirname, '/dist/index.js'), - 'utf8' - ); - assert(file.includes('function Foo')); - assert(file.includes('function Bar')); + let file = await fs.readFile( + path.join(__dirname, '/dist/index.js'), + 'utf8' + ); + assert(file.includes('function Foo')); + assert(file.includes('function Bar')); + } catch (e) { + if (e.perm == 'EPERM') { + symlinkPrivilegeWarning(); + this.skip(); + } + } }); it('should not compile node_modules with a source field in package.json when not symlinked', async function() { diff --git a/packages/core/integration-tests/test/kotlin.js b/packages/core/integration-tests/test/kotlin.js index 0e62f88133d..43ddbcdc7a9 100644 --- a/packages/core/integration-tests/test/kotlin.js +++ b/packages/core/integration-tests/test/kotlin.js @@ -1,7 +1,16 @@ const assert = require('assert'); -const {bundle, assertBundleTree, run} = require('./utils'); +const {bundle, assertBundleTree, run} = require('@parcel/test-utils'); +const commandExists = require('command-exists'); describe('kotlin', function() { + if (!commandExists.sync('java')) { + // eslint-disable-next-line no-console + console.log( + 'Skipping Kotlin tests. Install https://www.java.com/download/ to run them.' + ); + return; + } + it('should produce a basic kotlin bundle', async function() { let b = await bundle(__dirname + '/integration/kotlin/index.js'); diff --git a/packages/core/integration-tests/test/less.js b/packages/core/integration-tests/test/less.js index da522dd66d0..11bc5ca177f 100644 --- a/packages/core/integration-tests/test/less.js +++ b/packages/core/integration-tests/test/less.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('less', function() { it('should support requiring less files', async function() { diff --git a/packages/core/integration-tests/test/parser.js b/packages/core/integration-tests/test/parser.js index af10583255a..4d9fd37390f 100644 --- a/packages/core/integration-tests/test/parser.js +++ b/packages/core/integration-tests/test/parser.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, assertBundleTree} = require('./utils'); +const {bundle, assertBundleTree} = require('@parcel/test-utils'); describe('parser', function() { it('should support case-insensitive file extension', async function() { diff --git a/packages/core/integration-tests/test/pug.js b/packages/core/integration-tests/test/pug.js index 59198e60a7b..81f0d9fda7c 100644 --- a/packages/core/integration-tests/test/pug.js +++ b/packages/core/integration-tests/test/pug.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, assertBundleTree} = require('./utils'); +const {bundle, assertBundleTree} = require('@parcel/test-utils'); describe('pug', function() { it('should support bundling HTML', async function() { diff --git a/packages/core/integration-tests/test/reason.js b/packages/core/integration-tests/test/reason.js index 6356858d7ea..bf81dade629 100644 --- a/packages/core/integration-tests/test/reason.js +++ b/packages/core/integration-tests/test/reason.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const {bundle, run} = require('./utils'); +const {bundle, run} = require('@parcel/test-utils'); describe('reason', function() { it('should produce a bundle', async function() { diff --git a/packages/core/integration-tests/test/rust.js b/packages/core/integration-tests/test/rust.js index 90e4bd11b60..aa00fce6ed8 100644 --- a/packages/core/integration-tests/test/rust.js +++ b/packages/core/integration-tests/test/rust.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const {bundle, bundler, run, assertBundleTree} = require('./utils'); +const {bundle, bundler, run, assertBundleTree} = require('@parcel/test-utils'); const fs = require('@parcel/fs'); const commandExists = require('command-exists'); diff --git a/packages/core/integration-tests/test/sass.js b/packages/core/integration-tests/test/sass.js index 5febcbd0e64..245e3af66b1 100644 --- a/packages/core/integration-tests/test/sass.js +++ b/packages/core/integration-tests/test/sass.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('sass', function() { it('should support requiring sass files', async function() { diff --git a/packages/core/integration-tests/test/schema-jsonld.js b/packages/core/integration-tests/test/schema-jsonld.js index 5e7d24c1aec..24ead830864 100644 --- a/packages/core/integration-tests/test/schema-jsonld.js +++ b/packages/core/integration-tests/test/schema-jsonld.js @@ -1,4 +1,4 @@ -const {bundle, assertBundleTree} = require('./utils'); +const {bundle, assertBundleTree} = require('@parcel/test-utils'); describe('schema ld+json', function() { it('Should parse a LD+JSON schema and collect dependencies', async function() { diff --git a/packages/core/integration-tests/test/scope-hoisting.js b/packages/core/integration-tests/test/scope-hoisting.js index 0632164f044..d40a48f2ea2 100644 --- a/packages/core/integration-tests/test/scope-hoisting.js +++ b/packages/core/integration-tests/test/scope-hoisting.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const {bundle: _bundle, run} = require('./utils'); +const {bundle: _bundle, run} = require('@parcel/test-utils'); const fs = require('@parcel/fs'); const bundle = (name, opts = {}) => diff --git a/packages/core/integration-tests/test/server.js b/packages/core/integration-tests/test/server.js index 9dccf7ca8be..f5e18b07dab 100644 --- a/packages/core/integration-tests/test/server.js +++ b/packages/core/integration-tests/test/server.js @@ -2,7 +2,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); const logger = require('@parcel/logger'); -const {bundler} = require('./utils'); +const {bundler} = require('@parcel/test-utils'); const http = require('http'); const https = require('https'); const sinon = require('sinon'); diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index dad3d802d18..233915d50ab 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -2,7 +2,7 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); const mapValidator = require('sourcemap-validator'); -const {bundler, bundle, run, assertBundleTree} = require('./utils'); +const {bundler, bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('sourcemaps', function() { it('should create a valid sourcemap as a child of a JS bundle', async function() { diff --git a/packages/core/integration-tests/test/stylus.js b/packages/core/integration-tests/test/stylus.js index 40458ed46ed..f2dd3c087bc 100644 --- a/packages/core/integration-tests/test/stylus.js +++ b/packages/core/integration-tests/test/stylus.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('stylus', function() { it('should support requiring stylus files', async function() { diff --git a/packages/core/integration-tests/test/sugarss.js b/packages/core/integration-tests/test/sugarss.js index 6f0e18994df..f46fec12cb6 100644 --- a/packages/core/integration-tests/test/sugarss.js +++ b/packages/core/integration-tests/test/sugarss.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const {bundle, assertBundleTree} = require('./utils'); +const {bundle, assertBundleTree} = require('@parcel/test-utils'); const fs = require('@parcel/fs'); const path = require('path'); diff --git a/packages/core/integration-tests/test/typescript.js b/packages/core/integration-tests/test/typescript.js index 7aaada0a37b..ef792f5563e 100644 --- a/packages/core/integration-tests/test/typescript.js +++ b/packages/core/integration-tests/test/typescript.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('typescript', function() { it('should produce a ts bundle using ES6 imports', async function() { diff --git a/packages/core/integration-tests/test/utils.js b/packages/core/integration-tests/test/utils.js index e2f78fd517a..25ebdb32d9e 100644 --- a/packages/core/integration-tests/test/utils.js +++ b/packages/core/integration-tests/test/utils.js @@ -1,283 +1,5 @@ -const Bundler = require('parcel-bundler'); -const assert = require('assert'); -const vm = require('vm'); -const fs = require('@parcel/fs'); -const nodeFS = require('fs'); -const path = require('path'); -const WebSocket = require('ws'); -const Module = require('module'); - -const {promisify} = require('@parcel/utils'); -const {sleep} = require('@parcel/test-utils'); -const rimraf = promisify(require('rimraf')); -const ncp = promisify(require('ncp')); - -const chalk = new (require('chalk')).constructor({enabled: true}); -const warning = chalk.keyword('orange'); -// eslint-disable-next-line no-console -console.warn = (...args) => { - // eslint-disable-next-line no-console - console.error(warning(...args)); -}; - -async function removeDistDirectory(count = 0) { - try { - await rimraf(path.join(__dirname, 'dist')); - } catch (e) { - if (count > 8) { - // eslint-disable-next-line no-console - console.warn('WARNING: Unable to remove dist directory:', e.message); - return; - } - - await sleep(250); - await removeDistDirectory(count + 1); - } -} +const {removeDistDirectory} = require('@parcel/test-utils'); beforeEach(async function() { await removeDistDirectory(); }); - -function bundler(file, opts) { - return new Bundler( - file, - Object.assign( - { - outDir: path.join(__dirname, 'dist'), - watch: false, - cache: false, - killWorkers: false, - hmr: false, - logLevel: 0, - throwErrors: true - }, - opts - ) - ); -} - -function bundle(file, opts) { - return bundler(file, opts).bundle(); -} - -function prepareBrowserContext(bundle, globals) { - // for testing dynamic imports - const fakeElement = { - remove() {} - }; - - const fakeDocument = { - createElement(tag) { - return {tag}; - }, - - getElementsByTagName() { - return [ - { - appendChild(el) { - setTimeout(function() { - if (el.tag === 'script') { - vm.runInContext( - nodeFS.readFileSync( - path.join(path.dirname(bundle.name), el.src) - ), - ctx - ); - } - - el.onload(); - }, 0); - } - } - ]; - }, - - getElementById() { - return fakeElement; - }, - - body: { - appendChild() { - return null; - } - } - }; - - var exports = {}; - var ctx = Object.assign( - { - exports, - module: {exports}, - document: fakeDocument, - WebSocket, - console, - location: {hostname: 'localhost'}, - fetch(url) { - return Promise.resolve({ - arrayBuffer() { - return Promise.resolve( - new Uint8Array( - nodeFS.readFileSync(path.join(path.dirname(bundle.name), url)) - ).buffer - ); - }, - text() { - return Promise.resolve( - nodeFS.readFileSync( - path.join(path.dirname(bundle.name), url), - 'utf8' - ) - ); - } - }); - } - }, - globals - ); - - ctx.window = ctx; - return ctx; -} - -function prepareNodeContext(bundle, globals) { - var mod = new Module(bundle.name); - mod.paths = [path.dirname(bundle.name) + '/node_modules']; - - var ctx = Object.assign( - { - module: mod, - exports: module.exports, - __filename: bundle.name, - __dirname: path.dirname(bundle.name), - require: function(path) { - return mod.require(path); - }, - console, - process: process, - setTimeout: setTimeout, - setImmediate: setImmediate - }, - globals - ); - - ctx.global = ctx; - return ctx; -} - -async function run(bundle, globals, opts = {}) { - var ctx; - switch (bundle.entryAsset.options.target) { - case 'browser': - ctx = prepareBrowserContext(bundle, globals); - break; - case 'node': - ctx = prepareNodeContext(bundle, globals); - break; - case 'electron': - ctx = Object.assign( - prepareBrowserContext(bundle, globals), - prepareNodeContext(bundle, globals) - ); - break; - } - - vm.createContext(ctx); - vm.runInContext(await fs.readFile(bundle.name), ctx); - - if (opts.require !== false) { - if (ctx.parcelRequire) { - return ctx.parcelRequire(bundle.entryAsset.id); - } else if (ctx.output) { - return ctx.output; - } - if (ctx.module) { - return ctx.module.exports; - } - } - - return ctx; -} - -async function assertBundleTree(bundle, tree) { - if (tree.name) { - assert.equal( - path.basename(bundle.name), - tree.name, - 'bundle names mismatched' - ); - } - - if (tree.type) { - assert.equal( - bundle.type.toLowerCase(), - tree.type.toLowerCase(), - 'bundle types mismatched' - ); - } - - if (tree.assets) { - assert.deepEqual( - Array.from(bundle.assets) - .map(a => a.basename) - .sort(), - tree.assets.sort() - ); - } - - let childBundles = Array.isArray(tree) ? tree : tree.childBundles; - if (childBundles) { - let children = Array.from(bundle.childBundles).sort( - (a, b) => - Array.from(a.assets).sort()[0].basename < - Array.from(b.assets).sort()[0].basename - ? -1 - : 1 - ); - assert.equal( - bundle.childBundles.size, - childBundles.length, - 'expected number of child bundles mismatched' - ); - await Promise.all( - childBundles.map((b, i) => assertBundleTree(children[i], b)) - ); - } - - if (/js|css/.test(bundle.type)) { - assert(await fs.exists(bundle.name), 'expected file does not exist'); - } -} - -function nextBundle(b) { - return new Promise(resolve => { - b.once('bundled', resolve); - }); -} - -function deferred() { - let resolve, reject; - let promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - - promise.resolve = resolve; - promise.reject = reject; - - return promise; -} - -function normaliseNewlines(text) { - return text.replace(/(\r\n|\n|\r)/g, '\n'); -} - -exports.bundler = bundler; -exports.bundle = bundle; -exports.run = run; -exports.assertBundleTree = assertBundleTree; -exports.nextBundle = nextBundle; -exports.deferred = deferred; -exports.rimraf = rimraf; -exports.ncp = ncp; -exports.normaliseNewlines = normaliseNewlines; diff --git a/packages/core/integration-tests/test/vue.js b/packages/core/integration-tests/test/vue.js index c53dbb5220f..b27c5a7b4ea 100644 --- a/packages/core/integration-tests/test/vue.js +++ b/packages/core/integration-tests/test/vue.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const {bundle, assertBundleTree, run} = require('./utils'); +const {bundle, assertBundleTree, run} = require('@parcel/test-utils'); const fs = require('@parcel/fs'); describe('vue', function() { diff --git a/packages/core/integration-tests/test/wasm.js b/packages/core/integration-tests/test/wasm.js index 9fef9ef40cc..67a8eb51fcb 100644 --- a/packages/core/integration-tests/test/wasm.js +++ b/packages/core/integration-tests/test/wasm.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const {bundle, run, assertBundleTree, deferred} = require('./utils'); +const {bundle, run, assertBundleTree, deferred} = require('@parcel/test-utils'); describe('wasm', function() { if (typeof WebAssembly === 'undefined') { diff --git a/packages/core/integration-tests/test/watcher.js b/packages/core/integration-tests/test/watcher.js index 58bee8fb362..3426d3defc1 100644 --- a/packages/core/integration-tests/test/watcher.js +++ b/packages/core/integration-tests/test/watcher.js @@ -9,8 +9,9 @@ const { nextBundle, rimraf, ncp -} = require('./utils'); +} = require('@parcel/test-utils'); const {sleep} = require('@parcel/test-utils'); +const {symlinkPrivilegeWarning} = require('@parcel/test-utils'); const {symlinkSync} = require('fs'); const inputDir = path.join(__dirname, '/input'); @@ -274,29 +275,36 @@ describe('watcher', function() { inputDir ); - // Create the symlink here to prevent cross platform and git issues - symlinkSync( - path.join(inputDir, 'local.js'), - path.join(inputDir, 'src/symlinked_local.js') - ); - - b = bundler(path.join(inputDir, '/src/index.js'), { - watch: true - }); - - let bundle = await b.bundle(); - let output = await run(bundle); - - assert.equal(output(), 3); - - await sleep(100); - fs.writeFile( - path.join(inputDir, '/local.js'), - 'exports.a = 5; exports.b = 5;' - ); - - bundle = await nextBundle(b); - output = await run(bundle); - assert.equal(output(), 10); + try { + // Create the symlink here to prevent cross platform and git issues + symlinkSync( + path.join(inputDir, 'local.js'), + path.join(inputDir, 'src/symlinked_local.js') + ); + + b = bundler(path.join(inputDir, '/src/index.js'), { + watch: true + }); + + let bundle = await b.bundle(); + let output = await run(bundle); + + assert.equal(output(), 3); + + await sleep(100); + fs.writeFile( + path.join(inputDir, '/local.js'), + 'exports.a = 5; exports.b = 5;' + ); + + bundle = await nextBundle(b); + output = await run(bundle); + assert.equal(output(), 10); + } catch (e) { + if (e.code == 'EPERM') { + symlinkPrivilegeWarning(); + this.skip(); + } + } }); }); diff --git a/packages/core/parcel-bundler/test/asset.js b/packages/core/parcel-bundler/test/asset.js index 11f83118cba..a093f469493 100644 --- a/packages/core/parcel-bundler/test/asset.js +++ b/packages/core/parcel-bundler/test/asset.js @@ -2,7 +2,7 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); const Asset = require('../src/Asset'); -const {bundle} = require('./utils'); +const {bundle} = require('@parcel/test-utils'); describe('Asset', () => { it('should include default implementations', async () => { diff --git a/packages/core/parcel-bundler/test/autoinstall.js b/packages/core/parcel-bundler/test/autoinstall.js index 0aa5b8fb098..04dd294f1d1 100644 --- a/packages/core/parcel-bundler/test/autoinstall.js +++ b/packages/core/parcel-bundler/test/autoinstall.js @@ -1,7 +1,7 @@ const assert = require('assert'); const install = require('../src/utils/installPackage'); const fs = require('@parcel/fs'); -const {ncp, rimraf} = require('./utils'); +const {ncp, rimraf} = require('@parcel/test-utils'); const path = require('path'); const inputDirPath = path.join(__dirname, '/input'); diff --git a/packages/core/parcel-bundler/test/fs-cache.js b/packages/core/parcel-bundler/test/fs-cache.js index f868ce894fa..346f6912b30 100644 --- a/packages/core/parcel-bundler/test/fs-cache.js +++ b/packages/core/parcel-bundler/test/fs-cache.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); -const {rimraf, ncp} = require('./utils'); +const {rimraf, ncp} = require('@parcel/test-utils'); const {sleep} = require('@parcel/test-utils'); const FSCache = require('../src/FSCache'); diff --git a/packages/core/parcel-bundler/test/generateCertificate.js b/packages/core/parcel-bundler/test/generateCertificate.js index 844156eb7a0..b803ceaec49 100644 --- a/packages/core/parcel-bundler/test/generateCertificate.js +++ b/packages/core/parcel-bundler/test/generateCertificate.js @@ -2,7 +2,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('@parcel/fs'); const generateCertificate = require('../src/utils/generateCertificate'); -const {rimraf, ncp} = require('./utils'); +const {rimraf, ncp} = require('@parcel/test-utils'); const cachePath = path.join(__dirname, '.cache'); const inputPath = path.join(__dirname, '/input'); diff --git a/packages/core/parcel-bundler/test/plugins.js b/packages/core/parcel-bundler/test/plugins.js index c1510d8200f..d8e69fdb879 100644 --- a/packages/core/parcel-bundler/test/plugins.js +++ b/packages/core/parcel-bundler/test/plugins.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const {bundle, run, assertBundleTree} = require('./utils'); +const {bundle, run, assertBundleTree} = require('@parcel/test-utils'); describe('plugins', function() { it('should load plugins and apply custom asset type', async function() { diff --git a/packages/core/parcel-bundler/test/resolver.js b/packages/core/parcel-bundler/test/resolver.js index f16bdd7d9cd..6dcf1885667 100644 --- a/packages/core/parcel-bundler/test/resolver.js +++ b/packages/core/parcel-bundler/test/resolver.js @@ -1,35 +1,45 @@ const Resolver = require('../src/Resolver'); const path = require('path'); const assert = require('assert'); -const {rimraf, ncp} = require('./utils'); +const {rimraf, ncp} = require('@parcel/test-utils'); const {mkdirp} = require('@parcel/fs'); +const {symlinkPrivilegeWarning} = require('@parcel/test-utils'); const {symlinkSync} = require('fs'); const rootDir = path.join(__dirname, 'input/resolver'); describe('resolver', function() { let resolver; + let hasPrivilege = true; + before(async function() { await rimraf(path.join(__dirname, '/input')); await mkdirp(rootDir); await ncp(path.join(__dirname, 'integration/resolver'), rootDir); // Create the symlinks here to prevent cross platform and git issues - symlinkSync( - path.join(rootDir, 'packages/source'), - path.join(rootDir, 'node_modules/source'), - 'dir' - ); - symlinkSync( - path.join(rootDir, 'packages/source-alias'), - path.join(rootDir, 'node_modules/source-alias'), - 'dir' - ); - symlinkSync( - path.join(rootDir, 'packages/source-alias-glob'), - path.join(rootDir, 'node_modules/source-alias-glob'), - 'dir' - ); + try { + symlinkSync( + path.join(rootDir, 'packages/source'), + path.join(rootDir, 'node_modules/source'), + 'dir' + ); + symlinkSync( + path.join(rootDir, 'packages/source-alias'), + path.join(rootDir, 'node_modules/source-alias'), + 'dir' + ); + symlinkSync( + path.join(rootDir, 'packages/source-alias-glob'), + path.join(rootDir, 'node_modules/source-alias-glob'), + 'dir' + ); + } catch (e) { + if (e.code == 'EPERM') { + symlinkPrivilegeWarning(); + hasPrivilege = false; + } + } resolver = new Resolver({ rootDir, @@ -579,6 +589,8 @@ describe('resolver', function() { describe('source field', function() { it('should use the source field when symlinked', async function() { + if (!hasPrivilege) this.skip(); + let resolved = await resolver.resolve( 'source', path.join(rootDir, 'foo.js') @@ -591,6 +603,8 @@ describe('resolver', function() { }); it('should not use the source field when not symlinked', async function() { + if (!hasPrivilege) this.skip(); + let resolved = await resolver.resolve( 'source-not-symlinked', path.join(rootDir, 'foo.js') @@ -603,6 +617,8 @@ describe('resolver', function() { }); it('should use the source field as an alias when symlinked', async function() { + if (!hasPrivilege) this.skip(); + let resolved = await resolver.resolve( 'source-alias/dist', path.join(rootDir, 'foo.js') @@ -615,6 +631,8 @@ describe('resolver', function() { }); it('should use the source field as a glob alias when symlinked', async function() { + if (!hasPrivilege) this.skip(); + let resolved = await resolver.resolve( 'source-alias-glob', path.join(rootDir, 'foo.js') diff --git a/packages/core/parcel-bundler/test/utils.js b/packages/core/parcel-bundler/test/utils.js index f844538007c..25ebdb32d9e 100644 --- a/packages/core/parcel-bundler/test/utils.js +++ b/packages/core/parcel-bundler/test/utils.js @@ -1,283 +1,5 @@ -const Bundler = require('../src/Bundler'); -const assert = require('assert'); -const vm = require('vm'); -const fs = require('@parcel/fs'); -const nodeFS = require('fs'); -const path = require('path'); -const WebSocket = require('ws'); -const Module = require('module'); - -const {promisify} = require('@parcel/utils'); -const {sleep} = require('@parcel/test-utils'); -const rimraf = promisify(require('rimraf')); -const ncp = promisify(require('ncp')); - -const chalk = new (require('chalk')).constructor({enabled: true}); -const warning = chalk.keyword('orange'); -// eslint-disable-next-line no-console -console.warn = (...args) => { - // eslint-disable-next-line no-console - console.error(warning(...args)); -}; - -async function removeDistDirectory(count = 0) { - try { - await rimraf(path.join(__dirname, 'dist')); - } catch (e) { - if (count > 8) { - // eslint-disable-next-line no-console - console.warn('WARNING: Unable to remove dist directory:', e.message); - return; - } - - await sleep(250); - await removeDistDirectory(count + 1); - } -} +const {removeDistDirectory} = require('@parcel/test-utils'); beforeEach(async function() { await removeDistDirectory(); }); - -function bundler(file, opts) { - return new Bundler( - file, - Object.assign( - { - outDir: path.join(__dirname, 'dist'), - watch: false, - cache: false, - killWorkers: false, - hmr: false, - logLevel: 0, - throwErrors: true - }, - opts - ) - ); -} - -function bundle(file, opts) { - return bundler(file, opts).bundle(); -} - -function prepareBrowserContext(bundle, globals) { - // for testing dynamic imports - const fakeElement = { - remove() {} - }; - - const fakeDocument = { - createElement(tag) { - return {tag}; - }, - - getElementsByTagName() { - return [ - { - appendChild(el) { - setTimeout(function() { - if (el.tag === 'script') { - vm.runInContext( - nodeFS.readFileSync( - path.join(path.dirname(bundle.name), el.src) - ), - ctx - ); - } - - el.onload(); - }, 0); - } - } - ]; - }, - - getElementById() { - return fakeElement; - }, - - body: { - appendChild() { - return null; - } - } - }; - - var exports = {}; - var ctx = Object.assign( - { - exports, - module: {exports}, - document: fakeDocument, - WebSocket, - console, - location: {hostname: 'localhost'}, - fetch(url) { - return Promise.resolve({ - arrayBuffer() { - return Promise.resolve( - new Uint8Array( - nodeFS.readFileSync(path.join(path.dirname(bundle.name), url)) - ).buffer - ); - }, - text() { - return Promise.resolve( - nodeFS.readFileSync( - path.join(path.dirname(bundle.name), url), - 'utf8' - ) - ); - } - }); - } - }, - globals - ); - - ctx.window = ctx; - return ctx; -} - -function prepareNodeContext(bundle, globals) { - var mod = new Module(bundle.name); - mod.paths = [path.dirname(bundle.name) + '/node_modules']; - - var ctx = Object.assign( - { - module: mod, - exports: module.exports, - __filename: bundle.name, - __dirname: path.dirname(bundle.name), - require: function(path) { - return mod.require(path); - }, - console, - process: process, - setTimeout: setTimeout, - setImmediate: setImmediate - }, - globals - ); - - ctx.global = ctx; - return ctx; -} - -async function run(bundle, globals, opts = {}) { - var ctx; - switch (bundle.entryAsset.options.target) { - case 'browser': - ctx = prepareBrowserContext(bundle, globals); - break; - case 'node': - ctx = prepareNodeContext(bundle, globals); - break; - case 'electron': - ctx = Object.assign( - prepareBrowserContext(bundle, globals), - prepareNodeContext(bundle, globals) - ); - break; - } - - vm.createContext(ctx); - vm.runInContext(await fs.readFile(bundle.name), ctx); - - if (opts.require !== false) { - if (ctx.parcelRequire) { - return ctx.parcelRequire(bundle.entryAsset.id); - } else if (ctx.output) { - return ctx.output; - } - if (ctx.module) { - return ctx.module.exports; - } - } - - return ctx; -} - -async function assertBundleTree(bundle, tree) { - if (tree.name) { - assert.equal( - path.basename(bundle.name), - tree.name, - 'bundle names mismatched' - ); - } - - if (tree.type) { - assert.equal( - bundle.type.toLowerCase(), - tree.type.toLowerCase(), - 'bundle types mismatched' - ); - } - - if (tree.assets) { - assert.deepEqual( - Array.from(bundle.assets) - .map(a => a.basename) - .sort(), - tree.assets.sort() - ); - } - - let childBundles = Array.isArray(tree) ? tree : tree.childBundles; - if (childBundles) { - let children = Array.from(bundle.childBundles).sort( - (a, b) => - Array.from(a.assets).sort()[0].basename < - Array.from(b.assets).sort()[0].basename - ? -1 - : 1 - ); - assert.equal( - bundle.childBundles.size, - childBundles.length, - 'expected number of child bundles mismatched' - ); - await Promise.all( - childBundles.map((b, i) => assertBundleTree(children[i], b)) - ); - } - - if (/js|css/.test(bundle.type)) { - assert(await fs.exists(bundle.name), 'expected file does not exist'); - } -} - -function nextBundle(b) { - return new Promise(resolve => { - b.once('bundled', resolve); - }); -} - -function deferred() { - let resolve, reject; - let promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - - promise.resolve = resolve; - promise.reject = reject; - - return promise; -} - -function normaliseNewlines(text) { - return text.replace(/(\r\n|\n|\r)/g, '\n'); -} - -exports.bundler = bundler; -exports.bundle = bundle; -exports.run = run; -exports.assertBundleTree = assertBundleTree; -exports.nextBundle = nextBundle; -exports.deferred = deferred; -exports.rimraf = rimraf; -exports.ncp = ncp; -exports.normaliseNewlines = normaliseNewlines; diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index 4cdf552655a..10a8cd1649f 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -1,5 +1,297 @@ +const Bundler = require('parcel-bundler'); +const assert = require('assert'); +const vm = require('vm'); +const fs = require('@parcel/fs'); +const nodeFS = require('fs'); +const path = require('path'); +const WebSocket = require('ws'); +const Module = require('module'); + +const {promisify} = require('@parcel/utils'); +//const {sleep} = require('@parcel/test-utils'); +const rimraf = promisify(require('rimraf')); +const ncp = promisify(require('ncp')); + +const chalk = new (require('chalk')).constructor({enabled: true}); +const warning = chalk.keyword('orange'); +// eslint-disable-next-line no-console +console.warn = (...args) => { + // eslint-disable-next-line no-console + console.error(warning(...args)); +}; + +async function removeDistDirectory(count = 0) { + try { + await rimraf(path.join(process.cwd(), 'test/dist')); + } catch (e) { + if (count > 8) { + // eslint-disable-next-line no-console + console.warn('WARNING: Unable to remove dist directory:', e.message); + return; + } + + await sleep(250); + await removeDistDirectory(count + 1); + } +} + function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } +function symlinkPrivilegeWarning() { + // eslint-disable-next-line no-console + console.warn( + `----------------------------------- +Skipping symbolic link test(s) because you don't have the privilege. +Run tests with Administrator privilege. +If you don't know how, check here: https://bit.ly/2UmWsbD +-----------------------------------` + ); +} + +function bundler(file, opts) { + return new Bundler( + file, + Object.assign( + { + outDir: path.join(process.cwd(), 'test/dist'), + watch: false, + cache: false, + killWorkers: false, + hmr: false, + logLevel: 0, + throwErrors: true + }, + opts + ) + ); +} + +function bundle(file, opts) { + return bundler(file, opts).bundle(); +} + +async function run(bundle, globals, opts = {}) { + var ctx; + switch (bundle.entryAsset.options.target) { + case 'browser': + ctx = prepareBrowserContext(bundle, globals); + break; + case 'node': + ctx = prepareNodeContext(bundle, globals); + break; + case 'electron': + ctx = Object.assign( + prepareBrowserContext(bundle, globals), + prepareNodeContext(bundle, globals) + ); + break; + } + + vm.createContext(ctx); + vm.runInContext(await fs.readFile(bundle.name), ctx); + + if (opts.require !== false) { + if (ctx.parcelRequire) { + return ctx.parcelRequire(bundle.entryAsset.id); + } else if (ctx.output) { + return ctx.output; + } + if (ctx.module) { + return ctx.module.exports; + } + } + + return ctx; +} + +async function assertBundleTree(bundle, tree) { + if (tree.name) { + assert.equal( + path.basename(bundle.name), + tree.name, + 'bundle names mismatched' + ); + } + + if (tree.type) { + assert.equal( + bundle.type.toLowerCase(), + tree.type.toLowerCase(), + 'bundle types mismatched' + ); + } + + if (tree.assets) { + assert.deepEqual( + Array.from(bundle.assets) + .map(a => a.basename) + .sort(), + tree.assets.sort() + ); + } + + let childBundles = Array.isArray(tree) ? tree : tree.childBundles; + if (childBundles) { + let children = Array.from(bundle.childBundles).sort( + (a, b) => + Array.from(a.assets).sort()[0].basename < + Array.from(b.assets).sort()[0].basename + ? -1 + : 1 + ); + assert.equal( + bundle.childBundles.size, + childBundles.length, + 'expected number of child bundles mismatched' + ); + await Promise.all( + childBundles.map((b, i) => assertBundleTree(children[i], b)) + ); + } + + if (/js|css/.test(bundle.type)) { + assert(await fs.exists(bundle.name), 'expected file does not exist'); + } +} + +function nextBundle(b) { + return new Promise(resolve => { + b.once('bundled', resolve); + }); +} + +function deferred() { + let resolve, reject; + let promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + + promise.resolve = resolve; + promise.reject = reject; + + return promise; +} + +function normaliseNewlines(text) { + return text.replace(/(\r\n|\n|\r)/g, '\n'); +} + +function prepareBrowserContext(bundle, globals) { + // for testing dynamic imports + const fakeElement = { + remove() {} + }; + + const fakeDocument = { + createElement(tag) { + return {tag}; + }, + + getElementsByTagName() { + return [ + { + appendChild(el) { + setTimeout(function() { + if (el.tag === 'script') { + vm.runInContext( + nodeFS.readFileSync( + path.join(path.dirname(bundle.name), el.src) + ), + ctx + ); + } + + el.onload(); + }, 0); + } + } + ]; + }, + + getElementById() { + return fakeElement; + }, + + body: { + appendChild() { + return null; + } + } + }; + + var exports = {}; + var ctx = Object.assign( + { + exports, + module: {exports}, + document: fakeDocument, + WebSocket, + console, + location: {hostname: 'localhost'}, + fetch(url) { + return Promise.resolve({ + arrayBuffer() { + return Promise.resolve( + new Uint8Array( + nodeFS.readFileSync(path.join(path.dirname(bundle.name), url)) + ).buffer + ); + }, + text() { + return Promise.resolve( + nodeFS.readFileSync( + path.join(path.dirname(bundle.name), url), + 'utf8' + ) + ); + } + }); + } + }, + globals + ); + + ctx.window = ctx; + return ctx; +} + +function prepareNodeContext(bundle, globals) { + var mod = new Module(bundle.name); + mod.paths = [path.dirname(bundle.name) + '/node_modules']; + + var ctx = Object.assign( + { + module: mod, + exports: module.exports, + __filename: bundle.name, + __dirname: path.dirname(bundle.name), + require: function(path) { + return mod.require(path); + }, + console, + process: process, + setTimeout: setTimeout, + setImmediate: setImmediate + }, + globals + ); + + ctx.global = ctx; + return ctx; +} + exports.sleep = sleep; +exports.removeDistDirectory = removeDistDirectory; +exports.symlinkPrivilegeWarning = symlinkPrivilegeWarning; +exports.bundler = bundler; +exports.bundle = bundle; +exports.run = run; +exports.assertBundleTree = assertBundleTree; +exports.nextBundle = nextBundle; +exports.deferred = deferred; +exports.rimraf = rimraf; +exports.ncp = ncp; +exports.normaliseNewlines = normaliseNewlines;