From 76bfa255f6289c2e4dfe23395511635322a65d9e Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Sat, 2 Dec 2017 11:03:09 -0800 Subject: [PATCH 01/10] Convert testsuite to AVA --- .gitignore | 1 + package.json | 16 +- test/{util.js => _util.js} | 129 +++--- test/asar.js | 120 ++---- test/basic.js | 541 +++++++++++-------------- test/cli.js | 78 ++-- test/config.json | 1 - test/darwin.js | 797 +++++++++++++++++-------------------- test/hooks.js | 34 +- test/ignore.js | 194 ++++----- test/index.js | 59 --- test/infer.js | 201 ++++------ test/mas.js | 47 +-- test/prune.js | 103 ++--- test/targets.js | 39 +- test/win32.js | 90 ++--- 16 files changed, 1051 insertions(+), 1399 deletions(-) rename test/{util.js => _util.js} (56%) delete mode 100644 test/index.js diff --git a/.gitignore b/.gitignore index 8b704b2a..515b1d87 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.key *.pem node_modules +test/fixtures/basic/main-link.js test/work .DS_Store .nyc_output diff --git a/package.json b/package.json index 6d5a4133..ef040baa 100644 --- a/package.json +++ b/package.json @@ -37,19 +37,19 @@ "yargs-parser": "^8.0.0" }, "devDependencies": { + "ava": "^0.24.0", "buffer-equal": "^1.0.0", "coveralls": "^3.0.0", "eslint": "^4.1.0", "eslint-config-standard": "^10.0.0", + "eslint-plugin-ava": "^4.3.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-node": "^5.1.0", "eslint-plugin-promise": "^3.5.0", "eslint-plugin-standard": "^3.0.0", - "eslint-plugin-tape": "^1.1.0", "nyc": "^11.0.0", "pkg-up": "^2.0.0", - "rimraf": "^2.3.2", - "tape": "^4.0.0", + "tempy": "^0.2.1", "which": "^1.2.14" }, "engines": { @@ -58,8 +58,7 @@ "scripts": { "coveralls": "nyc report --reporter=text-lcov | coveralls", "lint": "eslint .", - "pretest": "rimraf test/work", - "test": "npm run lint && nyc tape test" + "test": "npm run lint && nyc ava test" }, "directories": { "test": "test" @@ -67,16 +66,16 @@ "keywords": [], "eslintConfig": { "extends": [ + "plugin:ava/recommended", "plugin:promise/recommended", - "plugin:tape/recommended", "standard" ], "parserOptions": { "sourceType": "script" }, "plugins": [ - "promise", - "tape" + "ava", + "promise" ], "rules": { "indent": [ @@ -89,6 +88,7 @@ "SwitchCase": 1 } ], + "ava/prefer-async-await": 0, "strict": "error" } } diff --git a/test/util.js b/test/_util.js similarity index 56% rename from test/util.js rename to test/_util.js index dff06f33..73ca16ce 100644 --- a/test/util.js +++ b/test/_util.js @@ -4,36 +4,74 @@ const bufferEqual = require('buffer-equal') const common = require('../common') const config = require('./config.json') +const exec = require('mz/child_process').exec const fs = require('fs-extra') const os = require('os') const packager = require('../index') const path = require('path') const targets = require('../targets') -const test = require('tape') +const tempy = require('tempy') +const test = require('ava') + +// Download all Electron distributions before running tests to avoid timing out due to network +// speed. Most tests run with the config.json version, but we have some tests using 0.37.4, and an +// electron module specific test using 1.3.1. +function preDownloadElectron () { + const versions = [ + config.version, + '0.37.4', + '1.3.1' + ] + return Promise.all(versions.map(exports.downloadAll)) +} + +function npmInstallForFixture (fixture) { + console.log(`Running npm install in fixtures/${fixture}...`) + return exec('npm install --no-bin-links', {cwd: exports.fixtureSubdir(fixture)}) + .catch((err) => console.error(err)) +} + +function npmInstallForFixtures () { + const fixtures = [ + 'basic', + 'basic-renamed-to-electron', + 'infer-missing-version-only', + 'el-0374' + ] + return Promise.all(fixtures.map(npmInstallForFixture)) +} const ORIGINAL_CWD = process.cwd() const WORK_CWD = path.join(__dirname, 'work') -// tape doesn't seem to have a provision for before/beforeEach/afterEach/after, -// so run setup/teardown and cleanup tasks as additional "tests" to put them in sequence -// and run them irrespective of test failures - -function setup () { - test('setup', (t) => { - fs.mkdirp(WORK_CWD) - .then(() => { - process.chdir(WORK_CWD) - return t.end() - }).catch(t.end) - }) +function ensureWorkDirExists () { + return fs.mkdirs(WORK_CWD).then(() => process.chdir(WORK_CWD)) } -function teardown () { - test('teardown', (t) => { - process.chdir(ORIGINAL_CWD) - fs.remove(WORK_CWD).then(t.end).catch(t.end) - }) -} +test.before(t => + preDownloadElectron() + .then(npmInstallForFixtures) + .catch(error => { + console.error(error.stack || error) + return process.exit(1) + }) + .then(ensureWorkDirExists) +) + +test.after.always(t => { + process.chdir(ORIGINAL_CWD) + return fs.remove(WORK_CWD) +}) + +test.beforeEach(t => { + t.context.workDir = tempy.directory() + t.context.tempDir = tempy.directory() +}) + +test.afterEach.always(t => { + return fs.remove(t.context.workDir) + .then(() => fs.remove(t.context.tempDir)) +}) exports.allPlatformArchCombosCount = 8 @@ -67,18 +105,6 @@ exports.downloadAll = function downloadAll (version) { })) } -exports.testFailure = function testFailure (description, promise) { - return test(description, t => { - return promise().then(() => { - t.fail('expected error') - return t.end() - }).catch(err => { - t.ok(err, 'error returned') - return t.end() - }) - }) -} - exports.fixtureSubdir = function fixtureSubdir (subdir) { return path.join(__dirname, 'fixtures', subdir) } @@ -89,21 +115,8 @@ exports.generateResourcesPath = function generateResourcesPath (opts) { : 'resources' } -exports.getWorkCwd = function getWorkCwd () { - return WORK_CWD -} - exports.invalidOptionTest = function invalidOptionTest (opts) { - return (t) => { - return packager(opts) - .then( - paths => t.end('no paths returned'), - (err) => { - t.ok(err, 'error thrown') - return t.end() - } - ) - } + return t => t.throws(packager(opts)) } exports.packageAndEnsureResourcesPath = function packageAndEnsureResourcesPath (t, opts) { @@ -120,15 +133,29 @@ exports.packageAndEnsureResourcesPath = function packageAndEnsureResourcesPath ( } exports.packagerTest = function packagerTest (name, testFunction) { - setup() - test(name, testFunction) // eslint-disable-line tape/test-ended - teardown() + test(name, t => { + const opts = { + name: 'packagerTest', + out: t.context.workDir, + tmpdir: t.context.tempDir + } + return testFunction(t, opts) + }) } // Rest parameters are added (not behind a feature flag) in Node 6 -exports.testSinglePlatform = function testSinglePlatform (name, createTest /*, ...createTestArgs */) { - var args = Array.prototype.slice.call(arguments, 2) - exports.packagerTest(name, createTest.apply(null, [{platform: 'linux', arch: 'x64', electronVersion: config.version}].concat(args))) +exports.testSinglePlatform = function testSinglePlatform (name, testFunction /*, ...testFunctionArgs */) { + const args = Array.prototype.slice.call(arguments, 2) + exports.packagerTest(name, (t, opts) => { + Object.assign(opts, {platform: 'linux', arch: 'x64', electronVersion: config.version}) + return testFunction.apply(null, [t, opts].concat(args)) + }) +} + +exports.timeoutTest = function timeoutTest (multiplier) { + if (!multiplier) multiplier = 1 + + setTimeout(() => { throw new Error('Timed out') }, config.timeout * multiplier) } exports.verifyPackageExistence = function verifyPackageExistence (finalPaths) { diff --git a/test/asar.js b/test/asar.js index e3ef47ea..cced974f 100644 --- a/test/asar.js +++ b/test/asar.js @@ -1,91 +1,59 @@ 'use strict' const common = require('../common') -const config = require('./config.json') const fs = require('fs-extra') -const packager = require('..') const path = require('path') -const test = require('tape') -const util = require('./util') +const test = require('ava') +const util = require('./_util') -function createDefaultAppAsarTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'el0374Test' - opts.dir = path.join(__dirname, 'fixtures', 'el-0374') - opts.electronVersion = '0.37.4' +test('asar argument test: asar is not set', t => { + const asarOpts = common.createAsarOpts({}) + t.false(asarOpts, 'createAsarOpts returns false') +}) - var resourcesPath +test('asar argument test: asar is true', t => { + t.deepEqual(common.createAsarOpts({asar: true}), {}) +}) - packager(opts) - .then(paths => { - resourcesPath = path.join(paths[0], util.generateResourcesPath(opts)) - return fs.pathExists(path.join(resourcesPath, 'default_app.asar')) - }).then(exists => { - t.false(exists, 'The output directory should not contain the Electron default_app.asar file') - return t.end() - }).catch(t.end) - } -} +test('asar argument test: asar is not an Object or a bool', t => { + t.false(common.createAsarOpts({asar: 'string'}), 'createAsarOpts returns false') +}) -function createAsarTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) +util.testSinglePlatform('default_app.asar removal test', (t, opts) => { + util.timeoutTest() - opts.name = 'basicTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.asar = { - 'unpack': '*.pac', - 'unpackDir': 'dir_to_unpack' - } - let finalPath - let resourcesPath + opts.name = 'default_appASARTest' + opts.dir = util.fixtureSubdir('el-0374') + opts.electronVersion = '0.37.4' - packager(opts) - .then(paths => { - finalPath = paths[0] - return fs.stat(finalPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The expected output directory should exist') - resourcesPath = path.join(finalPath, util.generateResourcesPath(opts)) - return fs.stat(resourcesPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') - return fs.stat(path.join(resourcesPath, 'app.asar')) - }).then(stats => { - t.true(stats.isFile(), 'app.asar should exist under the resources subdirectory when opts.asar is true') - return fs.pathExists(path.join(resourcesPath, 'app')) - }).then(exists => { - t.false(exists, 'app subdirectory should NOT exist when app.asar is built') - return fs.stat(path.join(resourcesPath, 'app.asar.unpacked')) - }).then(stats => { - t.true(stats.isDirectory(), 'app.asar.unpacked should exist under the resources subdirectory when opts.asar_unpack is set some expression') - return fs.stat(path.join(resourcesPath, 'app.asar.unpacked', 'dir_to_unpack')) - }).then(stats => { - t.true(stats.isDirectory(), 'dir_to_unpack should exist under app.asar.unpacked subdirectory when opts.asar-unpack-dir is set dir_to_unpack') - return t.end() - }).catch(t.end) - } -} - -test('asar argument test: asar is not set', (t) => { - const asarOpts = common.createAsarOpts({}) - t.false(asarOpts, 'createAsarOpts returns false') - t.end() + return util.packageAndEnsureResourcesPath(t, opts) + .then(resourcesPath => fs.pathExists(path.join(resourcesPath, 'default_app.asar'))) + .then(exists => t.false(exists, 'The output directory should not contain the Electron default_app.asar file')) }) -test('asar argument test: asar is true', (t) => { - const asarOpts = common.createAsarOpts({asar: true}) - t.same(asarOpts, {}) - t.end() -}) +util.testSinglePlatform('asar test', (t, opts) => { + util.timeoutTest() -test('asar argument test: asar is not an Object or a bool', (t) => { - const asarOpts = common.createAsarOpts({asar: 'string'}) - t.false(asarOpts, 'createAsarOpts returns false') - t.end() + opts.name = 'asarTest' + opts.dir = util.fixtureSubdir('basic') + opts.asar = { + 'unpack': '*.pac', + 'unpackDir': 'dir_to_unpack' + } + let resourcesPath + + return util.packageAndEnsureResourcesPath(t, opts) + .then(generatedResourcesPath => { + resourcesPath = generatedResourcesPath + return fs.stat(path.join(resourcesPath, 'app.asar')) + }).then(stats => { + t.true(stats.isFile(), 'app.asar should exist under the resources subdirectory when opts.asar is true') + return fs.pathExists(path.join(resourcesPath, 'app')) + }).then(exists => { + t.false(exists, 'app subdirectory should NOT exist when app.asar is built') + return fs.stat(path.join(resourcesPath, 'app.asar.unpacked')) + }).then(stats => { + t.true(stats.isDirectory(), 'app.asar.unpacked should exist under the resources subdirectory when opts.asar_unpack is set some expression') + return fs.stat(path.join(resourcesPath, 'app.asar.unpacked', 'dir_to_unpack')) + }).then(stats => t.true(stats.isDirectory(), 'dir_to_unpack should exist under app.asar.unpacked subdirectory when opts.asar-unpack-dir is set dir_to_unpack')) }) - -util.testSinglePlatform('default_app.asar removal test', createDefaultAppAsarTest) -util.testSinglePlatform('asar test', createAsarTest) diff --git a/test/basic.js b/test/basic.js index b0f338f6..4b9c4785 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,12 +1,12 @@ 'use strict' const common = require('../common') -const config = require('./config.json') const fs = require('fs-extra') +const hostArch = require('../targets').hostArch const packager = require('..') const path = require('path') -const test = require('tape') -const util = require('./util') +const test = require('ava') +const util = require('./_util') // Generates a path to the generated app that reflects the name given in the options. // Returns the Helper.app location on darwin since the top-level .app is already tested for the @@ -19,253 +19,6 @@ function generateNamePath (opts) { return opts.name + (opts.platform === 'win32' ? '.exe' : '') } -function createDefaultsTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'defaultsTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - delete opts.platform - delete opts.arch - - let defaultOpts = { - arch: process.arch, - name: opts.name, - platform: process.platform - } - - var finalPath - var resourcesPath - - packager(opts) - .then(paths => { - t.true(Array.isArray(paths), 'packager call should resolve to an array') - t.equal(paths.length, 1, 'Single-target run should resolve to a 1-item array') - - finalPath = paths[0] - t.equal(finalPath, path.join(util.getWorkCwd(), common.generateFinalBasename(defaultOpts)), - 'Path should follow the expected format and be in the cwd') - return fs.stat(finalPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The expected output directory should exist') - resourcesPath = path.join(finalPath, util.generateResourcesPath(defaultOpts)) - return fs.stat(path.join(finalPath, generateNamePath(defaultOpts))) - }).then(stats => { - if (common.isPlatformMac(defaultOpts.platform)) { - t.true(stats.isDirectory(), 'The Helper.app should reflect opts.name') - } else { - t.true(stats.isFile(), 'The executable should reflect opts.name') - } - return fs.stat(resourcesPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') - return fs.pathExists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall')) - }).then(exists => { - t.false(exists, 'The output directory should NOT contain devDependencies by default (prune=true)') - return util.areFilesEqual(path.join(opts.dir, 'main.js'), path.join(resourcesPath, 'app', 'main.js')) - }).then(equal => { - t.true(equal, 'File under packaged app directory should match source file') - return util.areFilesEqual(path.join(opts.dir, 'ignore', 'this.txt'), - path.join(resourcesPath, 'app', 'ignore', 'this.txt')) - }).then(equal => { - t.true(equal, 'File under subdirectory of packaged app directory should match source file and not be ignored by default') - return fs.pathExists(path.join(resourcesPath, 'default_app')) - }).then(exists => { - t.false(exists, 'The output directory should not contain the Electron default app directory') - return fs.pathExists(path.join(resourcesPath, 'default_app.asar')) - }).then(exists => { - t.false(exists, 'The output directory should not contain the Electron default app asar file') - return t.end() - }).catch(t.end) - } -} - -function createOutTest (opts) { - return function (t) { - t.timeoutAfter(config.timeout) - - opts.name = 'outTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.out = 'dist' - - var finalPath - - packager(opts) - .then(paths => { - finalPath = paths[0] - t.equal(finalPath, path.join('dist', common.generateFinalBasename(opts)), - 'Path should follow the expected format and be under the folder specified in `out`') - return fs.stat(finalPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The expected output directory should exist') - return fs.stat(path.join(finalPath, util.generateResourcesPath(opts))) - }).then(stats => { - t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') - return t.end() - }).catch(t.end) - } -} - -function createOverwriteTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout * 2) // Multiplied since this test packages the application twice - - opts.name = 'overwriteTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - - var finalPath - var testPath - - packager(opts) - .then(paths => { - finalPath = paths[0] - return fs.stat(finalPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The expected output directory should exist') - // Create a dummy file to detect whether the output directory is replaced in subsequent runs - testPath = path.join(finalPath, 'test.txt') - return fs.writeFile(testPath, 'test') - }).then(() => packager(opts)) // Run again, defaulting to overwrite false - .then(paths => fs.stat(testPath)) - .then(stats => { - t.true(stats.isFile(), 'The existing output directory should exist as before (skipped by default)') - // Run a third time, explicitly setting overwrite to true - opts.overwrite = true - return packager(opts) - }).then(paths => fs.pathExists(testPath)) - .then(exists => { - t.false(exists, 'The output directory should be regenerated when overwrite is true') - return t.end() - }).catch(t.end) - } -} - -function createTmpdirTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'tmpdirTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.out = 'dist' - opts.tmpdir = path.join(util.getWorkCwd(), 'tmp') - - packager(opts) - .then(paths => fs.stat(path.join(opts.tmpdir, 'electron-packager'))) - .then(stats => { - t.true(stats.isDirectory(), 'The expected temp directory should exist') - return t.end() - }).catch(t.end) - } -} - -function createDisableTmpdirUsingTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'disableTmpdirTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.out = 'dist' - opts.tmpdir = false - - packager(opts) - .then(paths => fs.stat(paths[0])) - .then(stats => { - t.true(stats.isDirectory(), 'The expected out directory should exist') - return t.end() - }).catch(t.end) - } -} - -function createDisableSymlinkDereferencingTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'disableSymlinkDerefTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.out = 'dist' - opts.derefSymlinks = false - opts.asar = false - - const dest = path.join(opts.dir, 'main-link.js') - - const src = path.join(opts.dir, 'main.js') - fs.ensureSymlink(src, dest) - .then(() => packager(opts)) - .then(paths => { - const destLink = path.join(paths[0], 'resources', 'app', 'main-link.js') - return fs.lstat(destLink) - }).then(stats => { - t.true(stats.isSymbolicLink(), 'The expected file should still be a symlink.') - return fs.remove(dest) - }).then(t.end).catch(t.end) - } -} - -function createExtraResourceStringTest (platform) { - return (opts) => { - return (t) => { - t.timeoutAfter(config.timeout) - - const extra1Base = 'data1.txt' - const extra1Path = path.join(__dirname, 'fixtures', extra1Base) - - opts.name = 'extraResourceStringTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.out = 'dist' - opts.platform = platform - opts.extraResource = extra1Path - - util.packageAndEnsureResourcesPath(t, opts) - .then(resourcesPath => util.areFilesEqual(extra1Path, path.join(resourcesPath, extra1Base))) - .then(equal => { - t.true(equal, 'resource file data1.txt should match') - return t.end() - }).catch(t.end) - } - } -} - -function createExtraResourceArrayTest (platform) { - return (opts) => { - return (t) => { - t.timeoutAfter(config.timeout) - - const extra1Base = 'data1.txt' - const extra1Path = path.join(__dirname, 'fixtures', extra1Base) - const extra2Base = 'extrainfo.plist' - const extra2Path = path.join(__dirname, 'fixtures', extra2Base) - - opts.name = 'extraResourceArrayTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.out = 'dist' - opts.platform = platform - opts.extraResource = [extra1Path, extra2Path] - - let extra1DistPath - let extra2DistPath - - util.packageAndEnsureResourcesPath(t, opts) - .then(resourcesPath => { - extra1DistPath = path.join(resourcesPath, extra1Base) - extra2DistPath = path.join(resourcesPath, extra2Base) - return fs.pathExists(extra1DistPath) - }).then(exists => { - t.true(exists, 'resource file data1.txt exists') - return util.areFilesEqual(extra1Path, extra1DistPath) - }).then(equal => { - t.true(equal, 'resource file data1.txt should match') - return fs.pathExists(extra2DistPath) - }).then(exists => { - t.true(exists, 'resource file extrainfo.plist exists') - return util.areFilesEqual(extra2Path, extra2DistPath) - }).then(equal => { - t.true(equal, 'resource file extrainfo.plist should match') - return t.end() - }).catch(t.end) - } - } -} - test('setting the quiet option does not print messages', (t) => { const errorLog = console.error const warningLog = console.warn @@ -274,13 +27,12 @@ test('setting the quiet option does not print messages', (t) => { console.warn = (message) => { output += message } common.warning('warning', true) - t.equal('', output, 'quieted common.warning should not call console.warn') + t.is('', output, 'quieted common.warning should not call console.warn') common.info('info', true) - t.equal('', output, 'quieted common.info should not call console.error') + t.is('', output, 'quieted common.info should not call console.error') console.error = errorLog console.warn = warningLog - t.end() }) test('download argument test: download.{arch,platform,version} does not overwrite {arch,platform,version}', function (t) { @@ -294,23 +46,20 @@ test('download argument test: download.{arch,platform,version} does not overwrit } var downloadOpts = common.createDownloadOpts(opts, 'linux', 'x64') - t.same(downloadOpts, {arch: 'x64', platform: 'linux', version: '0.36.0'}) - t.end() + t.deepEqual(downloadOpts, {arch: 'x64', platform: 'linux', version: '0.36.0'}) }) -test('sanitize app name for use in file/directory names', (t) => { - t.equal('@username-package', common.sanitizeAppName('@username/package'), 'slash should be replaced') - t.end() +test('sanitize app name for use in file/directory names', t => { + t.is('@username-package', common.sanitizeAppName('@username/package'), 'slash should be replaced') }) -test('sanitize app name for use in the out directory name', (t) => { +test('sanitize app name for use in the out directory name', t => { let opts = { arch: 'x64', name: '@username/package-name', platform: 'linux' } - t.equal('@username-package-name-linux-x64', common.generateFinalBasename(opts), 'generateFinalBasename output should be sanitized') - t.end() + t.is('@username-package-name-linux-x64', common.generateFinalBasename(opts), 'generateFinalBasename output should be sanitized') }) test('cannot build apps where the name ends in " Helper"', (t) => { @@ -323,11 +72,8 @@ test('cannot build apps where the name ends in " Helper"', (t) => { return packager(opts) .then( - () => t.end('should not finish'), - (err) => { - t.equal(err.message, 'Application names cannot end in " Helper" due to limitations on macOS') - t.end() - } + () => { throw new Error('should not finish') }, + (err) => t.is(err.message, 'Application names cannot end in " Helper" due to limitations on macOS') ) }) @@ -345,64 +91,228 @@ test('deprecatedParameter moves value in deprecated param to new param if new pa t.false(opts.hasOwnProperty('not_overwritten_old'), 'not_overwritten_old property is not set') t.true(opts.hasOwnProperty('new'), 'new property is set') - t.equal('value', opts.new, 'new property is not overwritten') - t.end() + t.is('value', opts.new, 'new property is not overwritten') +}) + +util.testSinglePlatform('defaults test', (t, opts) => { + opts.name = 'defaultsTest' + opts.dir = util.fixtureSubdir('basic') + delete opts.platform + delete opts.arch + + let defaultOpts = { + arch: hostArch(), + name: opts.name, + platform: process.platform + } + + let finalPath + let resourcesPath + + return packager(opts) + .then(paths => { + t.true(Array.isArray(paths), 'packager call should resolve to an array') + t.is(paths.length, 1, 'Single-target run should resolve to a 1-item array') + + finalPath = paths[0] + t.is(finalPath, path.join(t.context.workDir, common.generateFinalBasename(defaultOpts)), + 'Path should follow the expected format and be in the cwd') + return fs.stat(finalPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The expected output directory should exist') + resourcesPath = path.join(finalPath, util.generateResourcesPath(defaultOpts)) + return fs.stat(path.join(finalPath, generateNamePath(defaultOpts))) + }).then(stats => { + if (common.isPlatformMac(defaultOpts.platform)) { + t.true(stats.isDirectory(), 'The Helper.app should reflect opts.name') + } else { + t.true(stats.isFile(), 'The executable should reflect opts.name') + } + return fs.stat(resourcesPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + return fs.pathExists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall')) + }).then(exists => { + t.false(exists, 'The output directory should NOT contain devDependencies by default (prune=true)') + return util.areFilesEqual(path.join(opts.dir, 'main.js'), path.join(resourcesPath, 'app', 'main.js')) + }).then(equal => { + t.true(equal, 'File under packaged app directory should match source file') + return util.areFilesEqual(path.join(opts.dir, 'ignore', 'this.txt'), + path.join(resourcesPath, 'app', 'ignore', 'this.txt')) + }).then(equal => { + t.true(equal, 'File under subdirectory of packaged app directory should match source file and not be ignored by default') + return fs.pathExists(path.join(resourcesPath, 'default_app')) + }).then(exists => { + t.false(exists, 'The output directory should not contain the Electron default app directory') + return fs.pathExists(path.join(resourcesPath, 'default_app.asar')) + }).then(exists => t.false(exists, 'The output directory should not contain the Electron default app asar file')) +}) + +util.testSinglePlatform('out test', (t, opts) => { + opts.name = 'outTest' + opts.dir = util.fixtureSubdir('basic') + opts.out = 'dist' + + let finalPath + + return packager(opts) + .then(paths => { + finalPath = paths[0] + t.is(finalPath, path.join('dist', common.generateFinalBasename(opts)), + 'Path should follow the expected format and be under the folder specified in `out`') + return fs.stat(finalPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The expected output directory should exist') + return fs.stat(path.join(finalPath, util.generateResourcesPath(opts))) + }).then(stats => t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory')) }) -util.testSinglePlatform('defaults test', createDefaultsTest) -util.testSinglePlatform('out test', createOutTest) -util.testSinglePlatform('overwrite test', createOverwriteTest) -util.testSinglePlatform('tmpdir test', createTmpdirTest) -util.testSinglePlatform('disable tmpdir test', createDisableTmpdirUsingTest) -util.testSinglePlatform('deref symlink test', createDisableSymlinkDereferencingTest) +util.testSinglePlatform('overwrite test', (t, opts) => { + opts.name = 'overwriteTest' + opts.dir = util.fixtureSubdir('basic') + + let finalPath + let testPath + + return packager(opts) + .then(paths => { + finalPath = paths[0] + return fs.stat(finalPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The expected output directory should exist') + // Create a dummy file to detect whether the output directory is replaced in subsequent runs + testPath = path.join(finalPath, 'test.txt') + return fs.writeFile(testPath, 'test') + }).then(() => packager(opts)) // Run again, defaulting to overwrite false + .then(paths => fs.stat(testPath)) + .then(stats => { + t.true(stats.isFile(), 'The existing output directory should exist as before (skipped by default)') + // Run a third time, explicitly setting overwrite to true + opts.overwrite = true + return packager(opts) + }).then(paths => fs.pathExists(testPath)) + .then(exists => t.false(exists, 'The output directory should be regenerated when overwrite is true')) +}) + +util.testSinglePlatform('tmpdir test', (t, opts) => { + opts.name = 'tmpdirTest' + opts.dir = path.join(__dirname, 'fixtures', 'basic') + opts.out = 'dist' + opts.tmpdir = path.join(t.context.workDir, 'tmp') + + return packager(opts) + .then(paths => fs.stat(path.join(opts.tmpdir, 'electron-packager'))) + .then(stats => t.true(stats.isDirectory(), 'The expected temp directory should exist')) +}) + +util.testSinglePlatform('disable tmpdir test', (t, opts) => { + opts.name = 'disableTmpdirTest' + opts.dir = util.fixtureSubdir('basic') + opts.out = 'dist' + opts.tmpdir = false + + return packager(opts) + .then(paths => fs.stat(paths[0])) + .then(stats => t.true(stats.isDirectory(), 'The expected out directory should exist')) +}) + +util.testSinglePlatform('deref symlink test', (t, opts) => { + opts.name = 'disableSymlinkDerefTest' + opts.dir = util.fixtureSubdir('basic') + opts.derefSymlinks = false + + const src = path.join(opts.dir, 'main.js') + const dest = path.join(opts.dir, 'main-link.js') + + return fs.ensureSymlink(src, dest) + .then(() => packager(opts)) + .then(paths => { + const destLink = path.join(paths[0], 'resources', 'app', 'main-link.js') + return fs.lstat(destLink) + }).then(stats => { + t.true(stats.isSymbolicLink(), 'The expected file should still be a symlink') + return fs.remove(dest) + }) +}) + +function createExtraResourceStringTest (t, opts, platform) { + const extra1Base = 'data1.txt' + const extra1Path = path.join(__dirname, 'fixtures', extra1Base) + + opts.name = 'extraResourceStringTest' + opts.dir = util.fixtureSubdir('basic') + opts.out = 'dist' + opts.platform = platform + opts.extraResource = extra1Path + + return util.packageAndEnsureResourcesPath(t, opts) + .then(resourcesPath => util.areFilesEqual(extra1Path, path.join(resourcesPath, extra1Base))) + .then(equal => t.true(equal, 'resource file data1.txt should match')) +} + +function createExtraResourceArrayTest (t, opts, platform) { + const extra1Base = 'data1.txt' + const extra1Path = path.join(__dirname, 'fixtures', extra1Base) + const extra2Base = 'extrainfo.plist' + const extra2Path = path.join(__dirname, 'fixtures', extra2Base) + + opts.name = 'extraResourceArrayTest' + opts.dir = util.fixtureSubdir('basic') + opts.out = 'dist' + opts.platform = platform + opts.extraResource = [extra1Path, extra2Path] + + let extra1DistPath + let extra2DistPath + + return util.packageAndEnsureResourcesPath(t, opts) + .then(resourcesPath => { + extra1DistPath = path.join(resourcesPath, extra1Base) + extra2DistPath = path.join(resourcesPath, extra2Base) + return fs.pathExists(extra1DistPath) + }).then(exists => { + t.true(exists, 'resource file data1.txt exists') + return util.areFilesEqual(extra1Path, extra1DistPath) + }).then(equal => { + t.true(equal, 'resource file data1.txt should match') + return fs.pathExists(extra2DistPath) + }).then(exists => { + t.true(exists, 'resource file extrainfo.plist exists') + return util.areFilesEqual(extra2Path, extra2DistPath) + }).then(equal => t.true(equal, 'resource file extrainfo.plist should match')) +} for (const platform of ['darwin', 'linux']) { - util.testSinglePlatform(`extraResource test: string (${platform})`, createExtraResourceStringTest(platform)) - util.testSinglePlatform(`extraResource test: array (${platform})`, createExtraResourceArrayTest(platform)) + util.testSinglePlatform(`extraResource test: string (${platform})`, createExtraResourceStringTest, platform) + util.testSinglePlatform(`extraResource test: array (${platform})`, createExtraResourceArrayTest, platform) } -util.packagerTest('building for Linux target sanitizes binary name', (t) => { - const opts = { - name: '@username/package-name', - dir: path.join(__dirname, 'fixtures', 'el-0374'), - electronVersion: '0.37.4', - arch: 'ia32', - platform: 'linux' - } +util.packagerTest('building for Linux target sanitizes binary name', (t, opts) => { + opts.name = '@username/package-name' + opts.dir = util.fixtureSubdir('basic') - packager(opts) + return packager(opts) .then(paths => { - t.equal(1, paths.length, '1 bundle created') + t.is(1, paths.length, '1 bundle created') return fs.stat(path.join(paths[0], '@username-package-name')) - }).then(stats => { - t.true(stats.isFile(), 'The sanitized binary filename should exist') - return t.end() - }).catch(t.end) + }).then(stats => t.true(stats.isFile(), 'The sanitized binary filename should exist')) }) -util.packagerTest('executableName honored when building for Linux target', (t) => { - const opts = { - name: 'PackageName', - executableName: 'my-package', - dir: path.join(__dirname, 'fixtures', 'el-0374'), - electronVersion: '0.37.4', - arch: 'ia32', - platform: 'linux' - } +util.packagerTest('executableName honored when building for Linux target', (t, opts) => { + opts.name = 'PackageName' + opts.executableName = 'my-package' + opts.dir = util.fixtureSubdir('basic') - packager(opts) + return packager(opts) .then(paths => { - t.equal(1, paths.length, '1 bundle created') + t.is(1, paths.length, '1 bundle created') return fs.stat(path.join(paths[0], 'my-package')) - }).then(stats => { - t.true(stats.isFile(), 'The executableName-based filename should exist') - return t.end() - }).catch(t.end) + }).then(stats => t.true(stats.isFile(), 'The executableName-based filename should exist')) }) util.packagerTest('fails with invalid version', util.invalidOptionTest({ name: 'invalidElectronTest', - dir: path.join(__dirname, 'fixtures', 'el-0374'), + dir: util.fixtureSubdir('el-0374'), electronVersion: '0.0.1', arch: 'x64', platform: 'linux', @@ -411,18 +321,11 @@ util.packagerTest('fails with invalid version', util.invalidOptionTest({ } })) -util.packagerTest('dir argument test: should work with relative path', (t) => { - const opts = { - name: 'ElectronTest', - dir: path.join('..', 'fixtures', 'el-0374'), - electronVersion: '0.37.4', - arch: 'x64', - platform: 'linux' - } +util.packagerTest('dir argument test: should work with relative path', (t, opts) => { + opts.name = 'ElectronTest' + opts.dir = path.join('..', 'fixtures', 'el-0374') + opts.electronVersion = '0.37.4' - packager(opts) - .then(paths => { - t.equal(path.join(__dirname, 'work', 'ElectronTest-linux-x64'), paths[0], 'paths returned') - return t.end() - }).catch(t.end) + return packager(opts) + .then(paths => t.is(path.join(t.context.workDir, 'ElectronTest-linux-x64'), paths[0], 'paths returned')) }) diff --git a/test/cli.js b/test/cli.js index 6ce97d34..f249be8f 100644 --- a/test/cli.js +++ b/test/cli.js @@ -1,80 +1,68 @@ 'use strict' const common = require('../common') -const test = require('tape') +const test = require('ava') -test('CLI argument test: --electron-version populates opts.electronVersion', (t) => { +test('CLI argument test: --electron-version populates opts.electronVersion', t => { let args = common.parseCLIArgs([]) - t.equal(args.electronVersion, undefined) + t.is(args.electronVersion, undefined) args = common.parseCLIArgs(['--electron-version=1.2.3']) - t.equal(args.electronVersion, '1.2.3') - t.end() + t.is(args.electronVersion, '1.2.3') }) -test('CLI argument test: --download.strictSSL default', function (t) { - var args = common.parseCLIArgs([]) +test('CLI argument test: --download.strictSSL default', t => { + const args = common.parseCLIArgs([]) t.true(args.download.strictSSL, 'default for --download.strictSSL is true') - t.end() }) -test('CLI argument test: --asar=true', function (t) { - var args = common.parseCLIArgs(['--asar=true']) - t.equal(args.asar, true) - t.end() +test('CLI argument test: --asar=true', t => { + const args = common.parseCLIArgs(['--asar=true']) + t.true(args.asar) }) -test('CLI argument test: using --asar overrides other --asar.options', (t) => { +test('CLI argument test: using --asar overrides other --asar.options', t => { let args = common.parseCLIArgs(['--asar', '--asar.unpack=*.node']) - t.equal(args.asar, true) + t.true(args.asar) args = common.parseCLIArgs(['--asar.unpack=*.node', '--asar']) - t.equal(args.asar, true) - t.end() + t.true(args.asar) }) -test('CLI argument test: --osx-sign=true', function (t) { - var args = common.parseCLIArgs(['--osx-sign=true']) - t.equal(args.osxSign, true) - t.end() +test('CLI argument test: --osx-sign=true', t => { + const args = common.parseCLIArgs(['--osx-sign=true']) + t.true(args.osxSign) }) -test('CLI argument test: --tmpdir=false', function (t) { - var args = common.parseCLIArgs(['--tmpdir=false']) - t.equal(args.tmpdir, false) - t.end() +test('CLI argument test: --tmpdir=false', t => { + const args = common.parseCLIArgs(['--tmpdir=false']) + t.false(args.tmpdir) }) -test('CLI argument test: --deref-symlinks default', function (t) { - var args = common.parseCLIArgs([]) - t.equal(args.derefSymlinks, true) - t.end() +test('CLI argument test: --deref-symlinks default', t => { + const args = common.parseCLIArgs([]) + t.true(args.derefSymlinks) }) -test('CLI argument test: --out always resolves to a string', (t) => { - var args = common.parseCLIArgs(['--out=1']) - t.equal(args.out, '1') - t.end() +test('CLI argument test: --out always resolves to a string', t => { + const args = common.parseCLIArgs(['--out=1']) + t.is(args.out, '1') }) -test('CLI argument test: --out without a value is the same as not passing --out', (t) => { - var args = common.parseCLIArgs(['--out']) - t.equal(args.out, null) - t.end() +test('CLI argument test: --out without a value is the same as not passing --out', t => { + const args = common.parseCLIArgs(['--out']) + t.is(args.out, null) }) -test('CLI argument test: --protocol with a corresponding --protocol-name', (t) => { - var args = common.parseCLIArgs(['--protocol=foo', '--protocol-name=Foo']) +test('CLI argument test: --protocol with a corresponding --protocol-name', t => { + const args = common.parseCLIArgs(['--protocol=foo', '--protocol-name=Foo']) t.deepEqual(args.protocols, [{schemes: ['foo'], name: 'Foo'}]) - t.end() }) -test('CLI argument test: --protocol without a corresponding --protocol-name', (t) => { - var args = common.parseCLIArgs(['--protocol=foo']) +test('CLI argument test: --protocol without a corresponding --protocol-name', t => { + const args = common.parseCLIArgs(['--protocol=foo']) t.deepEqual(args.protocols, undefined, 'no protocols have been fully defined') - t.end() }) -test('CLI argument test: multiple --protocol/--protocol-name argument pairs', (t) => { - var args = common.parseCLIArgs(['--protocol=foo', '--protocol-name=Foo', '--protocol=bar', '--protocol-name=Bar']) +test('CLI argument test: multiple --protocol/--protocol-name argument pairs', t => { + const args = common.parseCLIArgs(['--protocol=foo', '--protocol-name=Foo', '--protocol=bar', '--protocol-name=Bar']) t.deepEqual(args.protocols, [{schemes: ['foo'], name: 'Foo'}, {schemes: ['bar'], name: 'Bar'}]) - t.end() }) diff --git a/test/config.json b/test/config.json index 69059ba6..7d6ada01 100644 --- a/test/config.json +++ b/test/config.json @@ -1,5 +1,4 @@ { "timeout": 30000, - "macExecTimeout": 60000, "version": "0.35.6" } diff --git a/test/darwin.js b/test/darwin.js index 96910e4a..8feb64ef 100644 --- a/test/darwin.js +++ b/test/darwin.js @@ -7,8 +7,43 @@ const mac = require('../mac') const packager = require('..') const path = require('path') const plist = require('plist') -const test = require('tape') -const util = require('./util') +const test = require('ava') +const util = require('./_util') + +const darwinOpts = { + name: 'darwinTest', + dir: util.fixtureSubdir('basic'), + electronVersion: config.version, + arch: 'x64', + platform: 'darwin' +} + +const el0374Opts = Object.assign({}, darwinOpts, { + name: 'el0374Test', + dir: util.fixtureSubdir('el-0374'), + electronVersion: '0.37.4' +}) + +function testWrapper (testName, extraOpts, testFunction/*, ...extraArgs */) { + const extraArgs = Array.prototype.slice.call(arguments, 3) + + util.packagerTest(testName, (t, baseOpts) => { + util.timeoutTest(2) + const opts = Object.assign({}, baseOpts, extraOpts) + + return testFunction.apply(null, [t, opts].concat(extraArgs)) + }) +} + +function darwinTest (testName, testFunction/*, ...extraArgs */) { + const extraArgs = Array.prototype.slice.call(arguments, 2) + return testWrapper.apply(null, [testName, darwinOpts, testFunction].concat(extraArgs)) +} + +function electron0374Test (testName, testFunction) { + const extraArgs = Array.prototype.slice.call(arguments, 2) + return testWrapper.apply(null, [testName, el0374Opts, testFunction].concat(extraArgs)) +} function getHelperExecutablePath (helperName) { return path.join(`${helperName}.app`, 'Contents', 'MacOS', helperName) @@ -29,310 +64,218 @@ function packageAndParseInfoPlist (t, opts) { .then(paths => parseInfoPlist(t, opts, paths[0])) } -function createHelperAppPathsTest (baseOpts, expectedName) { - return (t) => { - t.timeoutAfter(config.timeout) - - const opts = Object.assign({}, baseOpts) - let frameworksPath +function helperAppPathsTest (t, baseOpts, extraOpts, expectedName) { + const opts = Object.assign(baseOpts, extraOpts) + let frameworksPath - if (!expectedName) { - expectedName = opts.name - } - - packager(opts) - .then(paths => { - frameworksPath = path.join(paths[0], `${expectedName}.app`, 'Contents', 'Frameworks') - // main Helper.app is already tested in basic test suite; test its executable and the other helpers - return fs.stat(path.join(frameworksPath, getHelperExecutablePath(`${expectedName} Helper`))) - }).then(stats => { - t.true(stats.isFile(), 'The Helper.app executable should reflect sanitized opts.name') - return fs.stat(path.join(frameworksPath, `${expectedName} Helper EH.app`)) - }).then(stats => { - t.true(stats.isDirectory(), 'The Helper EH.app should reflect sanitized opts.name') - return fs.stat(path.join(frameworksPath, getHelperExecutablePath(`${expectedName} Helper EH`))) - }).then(stats => { - t.true(stats.isFile(), 'The Helper EH.app executable should reflect sanitized opts.name') - return fs.stat(path.join(frameworksPath, `${expectedName} Helper NP.app`)) - }).then(stats => { - t.true(stats.isDirectory(), 'The Helper NP.app should reflect sanitized opts.name') - return fs.stat(path.join(frameworksPath, getHelperExecutablePath(`${expectedName} Helper NP`))) - }).then(stats => { - t.true(stats.isFile(), 'The Helper NP.app executable should reflect sanitized opts.name') - return t.end() - }).catch(t.end) + if (!expectedName) { + expectedName = opts.name } -} -function createIconTest (baseOpts, icon, iconPath) { - return (t) => { - t.timeoutAfter(config.timeout) + return packager(opts) + .then(paths => { + frameworksPath = path.join(paths[0], `${expectedName}.app`, 'Contents', 'Frameworks') + // main Helper.app is already tested in basic test suite; test its executable and the other helpers + return fs.stat(path.join(frameworksPath, getHelperExecutablePath(`${expectedName} Helper`))) + }).then(stats => { + t.true(stats.isFile(), 'The Helper.app executable should reflect sanitized opts.name') + return fs.stat(path.join(frameworksPath, `${expectedName} Helper EH.app`)) + }).then(stats => { + t.true(stats.isDirectory(), 'The Helper EH.app should reflect sanitized opts.name') + return fs.stat(path.join(frameworksPath, getHelperExecutablePath(`${expectedName} Helper EH`))) + }).then(stats => { + t.true(stats.isFile(), 'The Helper EH.app executable should reflect sanitized opts.name') + return fs.stat(path.join(frameworksPath, `${expectedName} Helper NP.app`)) + }).then(stats => { + t.true(stats.isDirectory(), 'The Helper NP.app should reflect sanitized opts.name') + return fs.stat(path.join(frameworksPath, getHelperExecutablePath(`${expectedName} Helper NP`))) + }).then(stats => t.true(stats.isFile(), 'The Helper NP.app executable should reflect sanitized opts.name')) +} - const opts = Object.assign({}, baseOpts, {icon: icon}) +function iconTest (t, opts, icon, iconPath) { + opts.icon = icon - let resourcesPath - let outputPath + let resourcesPath - packager(opts) - .then(paths => { - outputPath = paths[0] - resourcesPath = path.join(outputPath, util.generateResourcesPath(opts)) - return fs.stat(resourcesPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') - return parseInfoPlist(t, opts, outputPath) - }).then(obj => { - return util.areFilesEqual(iconPath, path.join(resourcesPath, obj.CFBundleIconFile)) - }).then(equal => { - t.true(equal, 'installed icon file should be identical to the specified icon file') - return t.end() - }).catch(t.end) - } + return util.packageAndEnsureResourcesPath(t, opts) + .then(generatedResourcesPath => { + resourcesPath = generatedResourcesPath + const outputPath = resourcesPath.replace(`${path.sep}${exports.generateResourcesPath(opts)}`, '') + return parseInfoPlist(t, opts, outputPath) + }).then(obj => { + return util.areFilesEqual(iconPath, path.join(resourcesPath, obj.CFBundleIconFile)) + }).then(equal => t.true(equal, 'installed icon file should be identical to the specified icon file')) } -function createExtendInfoTest (baseOpts, extraPathOrParams) { - return (t) => { - t.timeoutAfter(config.timeout) - - const opts = Object.assign({}, baseOpts, { - appBundleId: 'com.electron.extratest', - appCategoryType: 'public.app-category.music', - buildVersion: '3.2.1', - extendInfo: extraPathOrParams +function extendInfoTest (t, baseOpts, extraPathOrParams) { + util.timeoutTest() + + const opts = Object.assign({}, baseOpts, { + appBundleId: 'com.electron.extratest', + appCategoryType: 'public.app-category.music', + buildVersion: '3.2.1', + extendInfo: extraPathOrParams + }) + + return packageAndParseInfoPlist(t, opts) + .then(obj => { + t.is(obj.TestKeyString, 'String data', 'TestKeyString should come from extendInfo') + t.is(obj.TestKeyInt, 12345, 'TestKeyInt should come from extendInfo') + t.is(obj.TestKeyBool, true, 'TestKeyBool should come from extendInfo') + t.deepEqual(obj.TestKeyArray, ['public.content', 'public.data'], 'TestKeyArray should come from extendInfo') + t.deepEqual(obj.TestKeyDict, { Number: 98765, CFBundleVersion: '0.0.0' }, 'TestKeyDict should come from extendInfo') + t.is(obj.CFBundleVersion, opts.buildVersion, 'CFBundleVersion should reflect buildVersion argument') + t.is(obj.CFBundleIdentifier, 'com.electron.extratest', 'CFBundleIdentifier should reflect appBundleId argument') + t.is(obj.LSApplicationCategoryType, 'public.app-category.music', 'LSApplicationCategoryType should reflect appCategoryType argument') + return t.is(obj.CFBundlePackageType, 'APPL', 'CFBundlePackageType should be Electron default') }) - - packageAndParseInfoPlist(t, opts) - .then(obj => { - t.equal(obj.TestKeyString, 'String data', 'TestKeyString should come from extendInfo') - t.equal(obj.TestKeyInt, 12345, 'TestKeyInt should come from extendInfo') - t.equal(obj.TestKeyBool, true, 'TestKeyBool should come from extendInfo') - t.deepEqual(obj.TestKeyArray, ['public.content', 'public.data'], 'TestKeyArray should come from extendInfo') - t.deepEqual(obj.TestKeyDict, { Number: 98765, CFBundleVersion: '0.0.0' }, 'TestKeyDict should come from extendInfo') - t.equal(obj.CFBundleVersion, opts.buildVersion, 'CFBundleVersion should reflect buildVersion argument') - t.equal(obj.CFBundleIdentifier, 'com.electron.extratest', 'CFBundleIdentifier should reflect appBundleId argument') - t.equal(obj.LSApplicationCategoryType, 'public.app-category.music', 'LSApplicationCategoryType should reflect appCategoryType argument') - t.equal(obj.CFBundlePackageType, 'APPL', 'CFBundlePackageType should be Electron default') - return t.end() - }).catch(t.end) - } } -function createBinaryNameTest (baseOpts, expectedExecutableName, expectedAppName) { - return (t) => { - t.timeoutAfter(config.timeout) +function binaryNameTest (t, baseOpts, extraOpts, expectedExecutableName, expectedAppName) { + const opts = Object.assign({}, baseOpts, extraOpts) + const appName = expectedAppName || expectedExecutableName || opts.name + const executableName = expectedExecutableName || opts.name - const opts = Object.assign({}, baseOpts) - let binaryPath - const appName = expectedAppName || expectedExecutableName || opts.name - const executableName = expectedExecutableName || opts.name + let binaryPath - packager(opts) - .then(paths => { - binaryPath = path.join(paths[0], `${appName}.app`, 'Contents', 'MacOS') - return fs.stat(path.join(binaryPath, executableName)) - }).then(stats => { - t.true(stats.isFile(), 'The binary should reflect a sanitized opts.name') - return t.end() - }).catch(t.end) - } + return packager(opts) + .then(paths => { + binaryPath = path.join(paths[0], `${appName}.app`, 'Contents', 'MacOS') + return fs.stat(path.join(binaryPath, executableName)) + }).then(stats => t.true(stats.isFile(), 'The binary should reflect a sanitized opts.name')) } -function createAppVersionTest (baseOpts, appVersion, buildVersion) { - return (t) => { - t.timeoutAfter(config.timeout) - - let opts = Object.assign({}, baseOpts, {appVersion: appVersion, buildVersion: appVersion}) - - if (buildVersion) { - opts.buildVersion = buildVersion - } +function appVersionTest (t, opts, appVersion, buildVersion) { + opts.appVersion = appVersion + opts.buildVersion = buildVersion || appVersion - packageAndParseInfoPlist(t, opts) - .then(obj => { - t.equal(obj.CFBundleVersion, '' + opts.buildVersion, 'CFBundleVersion should reflect buildVersion') - t.equal(obj.CFBundleShortVersionString, '' + opts.appVersion, 'CFBundleShortVersionString should reflect appVersion') - t.equal(typeof obj.CFBundleVersion, 'string', 'CFBundleVersion should be a string') - t.equal(typeof obj.CFBundleShortVersionString, 'string', 'CFBundleShortVersionString should be a string') - return t.end() - }).catch(t.end) - } + return packageAndParseInfoPlist(t, opts) + .then(obj => { + t.is(obj.CFBundleVersion, '' + opts.buildVersion, 'CFBundleVersion should reflect buildVersion') + t.is(obj.CFBundleShortVersionString, '' + opts.appVersion, 'CFBundleShortVersionString should reflect appVersion') + t.is(typeof obj.CFBundleVersion, 'string', 'CFBundleVersion should be a string') + return t.is(typeof obj.CFBundleShortVersionString, 'string', 'CFBundleShortVersionString should be a string') + }) } -function createAppVersionInferenceTest (baseOpts) { - return (t) => { - t.timeoutAfter(config.timeout) - - packageAndParseInfoPlist(t, Object.assign({}, baseOpts)) - .then(obj => { - t.equal(obj.CFBundleVersion, '4.99.101', 'CFBundleVersion should reflect package.json version') - t.equal(obj.CFBundleShortVersionString, '4.99.101', 'CFBundleShortVersionString should reflect package.json version') - return t.end() - }).catch(t.end) +function appBundleTest (t, opts, appBundleId) { + if (appBundleId) { + opts.appBundleId = appBundleId } -} -function createAppCategoryTypeTest (baseOpts, appCategoryType) { - return (t) => { - t.timeoutAfter(config.timeout) - - const opts = Object.assign({}, baseOpts, {appCategoryType: appCategoryType}) - - packageAndParseInfoPlist(t, opts) - .then(obj => { - t.equal(obj.LSApplicationCategoryType, opts.appCategoryType, 'LSApplicationCategoryType should reflect opts.appCategoryType') - return t.end() - }).catch(t.end) - } + const defaultBundleName = `com.electron.${opts.name.toLowerCase()}` + const appBundleIdentifier = mac.filterCFBundleIdentifier(opts.appBundleId || defaultBundleName) + + return packageAndParseInfoPlist(t, opts) + .then(obj => { + t.is(obj.CFBundleDisplayName, opts.name, 'CFBundleDisplayName should reflect opts.name') + t.is(obj.CFBundleName, opts.name, 'CFBundleName should reflect opts.name') + t.is(obj.CFBundleIdentifier, appBundleIdentifier, 'CFBundleName should reflect opts.appBundleId or fallback to default') + t.is(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string') + t.is(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string') + t.is(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string') + return t.is(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') + }) } -function createAppBundleTest (baseOpts, appBundleId) { - return (t) => { - t.timeoutAfter(config.timeout) +function appHelpersBundleTest (t, opts, helperBundleId, appBundleId) { + let tempPath, plistPath - let opts = Object.assign({}, baseOpts) - if (appBundleId) { - opts.appBundleId = appBundleId - } - const defaultBundleName = `com.electron.${opts.name.toLowerCase()}` - const appBundleIdentifier = mac.filterCFBundleIdentifier(opts.appBundleId || defaultBundleName) - - packageAndParseInfoPlist(t, opts) - .then(obj => { - t.equal(obj.CFBundleDisplayName, opts.name, 'CFBundleDisplayName should reflect opts.name') - t.equal(obj.CFBundleName, opts.name, 'CFBundleName should reflect opts.name') - t.equal(obj.CFBundleIdentifier, appBundleIdentifier, 'CFBundleName should reflect opts.appBundleId or fallback to default') - t.equal(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string') - t.equal(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string') - t.equal(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string') - t.equal(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') - return t.end() - }).catch(t.end) + if (helperBundleId) { + opts.helperBundleId = helperBundleId } -} - -function createAppBundleFrameworkTest (baseOpts) { - return (t) => { - t.timeoutAfter(config.timeout) - - let frameworkPath - - packager(baseOpts) - .then(paths => { - frameworkPath = path.join(paths[0], `${baseOpts.name}.app`, 'Contents', 'Frameworks', 'Electron Framework.framework') - return fs.stat(frameworkPath) - }).then(stats => { - t.true(stats.isDirectory(), 'Expected Electron Framework.framework to be a directory') - return fs.lstat(path.join(frameworkPath, 'Electron Framework')) - }).then(stats => { - t.true(stats.isSymbolicLink(), 'Expected Electron Framework.framework/Electron Framework to be a symlink') - return fs.lstat(path.join(frameworkPath, 'Versions', 'Current')) - }).then(stats => { - t.true(stats.isSymbolicLink(), 'Expected Electron Framework.framework/Versions/Current to be a symlink') - return t.end() - }).catch(t.end) + if (appBundleId) { + opts.appBundleId = appBundleId } -} + const defaultBundleName = `com.electron.${opts.name.toLowerCase()}` + const appBundleIdentifier = mac.filterCFBundleIdentifier(opts.appBundleId || defaultBundleName) + const helperBundleIdentifier = mac.filterCFBundleIdentifier(opts.helperBundleId || appBundleIdentifier + '.helper') -function createAppHelpersBundleTest (baseOpts, helperBundleId, appBundleId) { - return (t) => { - t.timeoutAfter(config.timeout) - - let tempPath, plistPath - let opts = Object.assign({}, baseOpts) - if (helperBundleId) { - opts.helperBundleId = helperBundleId - } - if (appBundleId) { - opts.appBundleId = appBundleId - } - const defaultBundleName = `com.electron.${opts.name.toLowerCase()}` - const appBundleIdentifier = mac.filterCFBundleIdentifier(opts.appBundleId || defaultBundleName) - const helperBundleIdentifier = mac.filterCFBundleIdentifier(opts.helperBundleId || appBundleIdentifier + '.helper') - - packager(opts) - .then(paths => { - tempPath = paths[0] - plistPath = path.join(tempPath, opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper.app', 'Contents', 'Info.plist') - return fs.stat(plistPath) - }).then(stats => { - t.true(stats.isFile(), 'The expected Info.plist file should exist in helper app') - return fs.readFile(plistPath, 'utf8') - }).then(file => { - const obj = plist.parse(file) - t.equal(obj.CFBundleName, opts.name, 'CFBundleName should reflect opts.name in helper app') - t.equal(obj.CFBundleIdentifier, helperBundleIdentifier, 'CFBundleIdentifier should reflect opts.helperBundleId, opts.appBundleId or fallback to default in helper app') - t.equal(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string in helper app') - t.equal(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string in helper app') - t.equal(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') - // check helper EH - plistPath = path.join(tempPath, opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper EH.app', 'Contents', 'Info.plist') - return fs.stat(plistPath) - }).then(stats => { - t.true(stats.isFile(), 'The expected Info.plist file should exist in helper EH app') - return fs.readFile(plistPath, 'utf8') - }).then(file => { - const obj = plist.parse(file) - t.equal(obj.CFBundleName, opts.name + ' Helper EH', 'CFBundleName should reflect opts.name in helper EH app') - t.equal(obj.CFBundleDisplayName, opts.name + ' Helper EH', 'CFBundleDisplayName should reflect opts.name in helper EH app') - t.equal(obj.CFBundleExecutable, opts.name + ' Helper EH', 'CFBundleExecutable should reflect opts.name in helper EH app') - t.equal(obj.CFBundleIdentifier, helperBundleIdentifier + '.EH', 'CFBundleName should reflect opts.helperBundleId, opts.appBundleId or fallback to default in helper EH app') - t.equal(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string in helper EH app') - t.equal(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string in helper EH app') - t.equal(typeof obj.CFBundleExecutable, 'string', 'CFBundleExecutable should be a string in helper EH app') - t.equal(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string in helper EH app') - t.equal(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') - // check helper NP - plistPath = path.join(tempPath, opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper NP.app', 'Contents', 'Info.plist') - return fs.stat(plistPath) - }).then(stats => { - t.true(stats.isFile(), 'The expected Info.plist file should exist in helper NP app') - return fs.readFile(plistPath, 'utf8') - }).then(file => { - const obj = plist.parse(file) - t.equal(obj.CFBundleName, opts.name + ' Helper NP', 'CFBundleName should reflect opts.name in helper NP app') - t.equal(obj.CFBundleDisplayName, opts.name + ' Helper NP', 'CFBundleDisplayName should reflect opts.name in helper NP app') - t.equal(obj.CFBundleExecutable, opts.name + ' Helper NP', 'CFBundleExecutable should reflect opts.name in helper NP app') - t.equal(obj.CFBundleIdentifier, helperBundleIdentifier + '.NP', 'CFBundleName should reflect opts.helperBundleId, opts.appBundleId or fallback to default in helper NP app') - t.equal(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string in helper NP app') - t.equal(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string in helper NP app') - t.equal(typeof obj.CFBundleExecutable, 'string', 'CFBundleExecutable should be a string in helper NP app') - t.equal(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string in helper NP app') - t.equal(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') - return t.end() - }).catch(t.end) - } + return packager(opts) + .then(paths => { + tempPath = paths[0] + plistPath = path.join(tempPath, opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper.app', 'Contents', 'Info.plist') + return fs.stat(plistPath) + }).then(stats => { + t.true(stats.isFile(), 'The expected Info.plist file should exist in helper app') + return fs.readFile(plistPath, 'utf8') + }).then(file => { + const obj = plist.parse(file) + t.is(obj.CFBundleName, opts.name, 'CFBundleName should reflect opts.name in helper app') + t.is(obj.CFBundleIdentifier, helperBundleIdentifier, 'CFBundleIdentifier should reflect opts.helperBundleId, opts.appBundleId or fallback to default in helper app') + t.is(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string in helper app') + t.is(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string in helper app') + t.is(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') + // check helper EH + plistPath = path.join(tempPath, opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper EH.app', 'Contents', 'Info.plist') + return fs.stat(plistPath) + }).then(stats => { + t.true(stats.isFile(), 'The expected Info.plist file should exist in helper EH app') + return fs.readFile(plistPath, 'utf8') + }).then(file => { + const obj = plist.parse(file) + t.is(obj.CFBundleName, opts.name + ' Helper EH', 'CFBundleName should reflect opts.name in helper EH app') + t.is(obj.CFBundleDisplayName, opts.name + ' Helper EH', 'CFBundleDisplayName should reflect opts.name in helper EH app') + t.is(obj.CFBundleExecutable, opts.name + ' Helper EH', 'CFBundleExecutable should reflect opts.name in helper EH app') + t.is(obj.CFBundleIdentifier, helperBundleIdentifier + '.EH', 'CFBundleName should reflect opts.helperBundleId, opts.appBundleId or fallback to default in helper EH app') + t.is(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string in helper EH app') + t.is(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string in helper EH app') + t.is(typeof obj.CFBundleExecutable, 'string', 'CFBundleExecutable should be a string in helper EH app') + t.is(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string in helper EH app') + t.is(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') + // check helper NP + plistPath = path.join(tempPath, opts.name + '.app', 'Contents', 'Frameworks', opts.name + ' Helper NP.app', 'Contents', 'Info.plist') + return fs.stat(plistPath) + }).then(stats => { + t.true(stats.isFile(), 'The expected Info.plist file should exist in helper NP app') + return fs.readFile(plistPath, 'utf8') + }).then(file => { + const obj = plist.parse(file) + t.is(obj.CFBundleName, opts.name + ' Helper NP', 'CFBundleName should reflect opts.name in helper NP app') + t.is(obj.CFBundleDisplayName, opts.name + ' Helper NP', 'CFBundleDisplayName should reflect opts.name in helper NP app') + t.is(obj.CFBundleExecutable, opts.name + ' Helper NP', 'CFBundleExecutable should reflect opts.name in helper NP app') + t.is(obj.CFBundleIdentifier, helperBundleIdentifier + '.NP', 'CFBundleName should reflect opts.helperBundleId, opts.appBundleId or fallback to default in helper NP app') + t.is(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string in helper NP app') + t.is(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string in helper NP app') + t.is(typeof obj.CFBundleExecutable, 'string', 'CFBundleExecutable should be a string in helper NP app') + t.is(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string in helper NP app') + return t.is(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') + }) } -function createAppHumanReadableCopyrightTest (baseOpts, humanReadableCopyright) { - return (t) => { - t.timeoutAfter(config.timeout) +if (!(process.env.CI && process.platform === 'win32')) { + darwinTest('helper app paths test', helperAppPathsTest) + darwinTest('helper app paths test with app name needing sanitization', helperAppPathsTest, {name: '@username/package-name'}, '@username-package-name') - const opts = Object.assign({}, baseOpts, {appCopyright: humanReadableCopyright}) + const iconBase = path.join(__dirname, 'fixtures', 'monochrome') + const icnsPath = `${iconBase}.icns` - packageAndParseInfoPlist(t, opts) - .then(obj => { - t.equal(obj.NSHumanReadableCopyright, opts.appCopyright, 'NSHumanReadableCopyright should reflect opts.appCopyright') - return t.end() - }).catch(t.end) - } -} + darwinTest('icon test: .icns specified', iconTest, icnsPath, icnsPath) + // This test exists because the .icns file basename changed as of 0.37.4 + electron0374Test('icon test: Electron 0.37.4, .icns specified', iconTest, icnsPath, icnsPath) + darwinTest('icon test: .ico specified (should replace with .icns)', iconTest, `${iconBase}.ico`, icnsPath) + darwinTest('icon test: basename only (should add .icns)', iconTest, iconBase, icnsPath) + + const extraInfoPath = path.join(__dirname, 'fixtures', 'extrainfo.plist') + const extraInfoParams = plist.parse(fs.readFileSync(extraInfoPath).toString()) -function createProtocolTest (baseOpts) { - return (t) => { - t.timeoutAfter(config.timeout) + darwinTest('extendInfo by filename test', extendInfoTest, extraInfoPath) + darwinTest('extendInfo by params test', extendInfoTest, extraInfoParams) - const opts = Object.assign({}, baseOpts, { - protocols: [{ + darwinTest('protocol/protocol-name argument test', (t, opts) => { + opts.protocols = [ + { name: 'Foo', schemes: ['foo'] - }, { + }, + { name: 'Bar', schemes: ['bar', 'baz'] - }] - }) + } + ] - packageAndParseInfoPlist(t, opts) - .then(obj => { + return packageAndParseInfoPlist(t, opts) + .then(obj => t.deepEqual(obj.CFBundleURLTypes, [{ CFBundleURLName: 'Foo', CFBundleURLSchemes: ['foo'] @@ -340,176 +283,166 @@ function createProtocolTest (baseOpts) { CFBundleURLName: 'Bar', CFBundleURLSchemes: ['bar', 'baz'] }], 'CFBundleURLTypes did not contain specified protocol schemes and names') - return t.end() - }).catch(t.end) - } -} - -const baseOpts = { - name: 'basicTest', - dir: path.join(__dirname, 'fixtures', 'basic'), - electronVersion: config.version, - arch: 'x64', - platform: 'darwin' -} - -const iconBase = path.join(__dirname, 'fixtures', 'monochrome') -const icnsPath = `${iconBase}.icns` -const el0374Opts = Object.assign({}, baseOpts, { - name: 'el0374Test', - dir: util.fixtureSubdir('el-0374'), - electronVersion: '0.37.4' -}) -const extraInfoPath = path.join(__dirname, 'fixtures', 'extrainfo.plist') -const extraInfoParams = plist.parse(fs.readFileSync(extraInfoPath).toString()) - -util.packagerTest('helper app paths test', createHelperAppPathsTest(baseOpts)) -util.packagerTest('helper app paths test with app name needing sanitization', createHelperAppPathsTest(Object.assign({}, baseOpts, {name: '@username/package-name'}), '@username-package-name')) - -util.packagerTest('icon test: .icns specified', createIconTest(baseOpts, icnsPath, icnsPath)) -// This test exists because the .icns file basename changed as of 0.37.4 -util.packagerTest('icon test: el-0.37.4, .icns specified', createIconTest(el0374Opts, icnsPath, icnsPath)) -util.packagerTest('icon test: .ico specified (should replace with .icns)', createIconTest(baseOpts, `${iconBase}.ico`, icnsPath)) -util.packagerTest('icon test: basename only (should add .icns)', createIconTest(baseOpts, iconBase, icnsPath)) - -util.packagerTest('extendInfo by filename test', createExtendInfoTest(baseOpts, extraInfoPath)) -util.packagerTest('extendInfo by params test', createExtendInfoTest(baseOpts, extraInfoParams)) - -util.packagerTest('protocol/protocol-name argument test', createProtocolTest(baseOpts)) - -test('osxSign argument test: default args', (t) => { - const args = true - const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') - t.same(signOpts, {identity: null, app: 'out', platform: 'darwin', version: 'version'}) - return t.end() -}) - -test('osxSign argument test: identity=true sets autodiscovery mode', (t) => { - const args = {identity: true} - const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') - t.same(signOpts, {identity: null, app: 'out', platform: 'darwin', version: 'version'}) - return t.end() -}) - -test('osxSign argument test: entitlements passed to electron-osx-sign', (t) => { - const args = {entitlements: 'path-to-entitlements'} - const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') - t.same(signOpts, {app: 'out', platform: 'darwin', version: 'version', entitlements: args.entitlements}) - return t.end() -}) - -test('osxSign argument test: app not overwritten', (t) => { - const args = {app: 'some-other-path'} - const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') - t.same(signOpts, {app: 'out', platform: 'darwin', version: 'version'}) - return t.end() -}) - -test('osxSign argument test: platform not overwritten', (t) => { - const args = {platform: 'mas'} - const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') - t.same(signOpts, {app: 'out', platform: 'darwin', version: 'version'}) - return t.end() -}) - -test('osxSign argument test: binaries not set', (t) => { - const args = {binaries: ['binary1', 'binary2']} - const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') - t.same(signOpts, {app: 'out', platform: 'darwin', version: 'version'}) - return t.end() -}) - -util.packagerTest('codesign test', (t) => { - t.timeoutAfter(config.macExecTimeout) - - const opts = Object.assign({}, baseOpts, {osxSign: {identity: 'Developer CodeCert'}}) - let appPath - - packager(opts) - .then(paths => { - appPath = path.join(paths[0], opts.name + '.app') - return fs.stat(appPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The expected .app directory should exist') - return exec(`codesign -v ${appPath}`) - }).then( - (stdout, stderr) => { - t.pass('codesign should verify successfully') - return t.end() - }, - (err) => { - const notFound = err && err.code === 127 - if (notFound) console.log('codesign not installed; skipped') - return t.end(notFound ? null : err) - } - ).catch(t.end) -}) + ) + }) + + test('osxSign argument test: default args', t => { + const args = true + const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') + t.deepEqual(signOpts, {identity: null, app: 'out', platform: 'darwin', version: 'version'}) + }) + + test('osxSign argument test: identity=true sets autodiscovery mode', t => { + const args = {identity: true} + const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') + t.deepEqual(signOpts, {identity: null, app: 'out', platform: 'darwin', version: 'version'}) + }) + + test('osxSign argument test: entitlements passed to electron-osx-sign', t => { + const args = {entitlements: 'path-to-entitlements'} + const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') + t.deepEqual(signOpts, {app: 'out', platform: 'darwin', version: 'version', entitlements: args.entitlements}) + }) + + test('osxSign argument test: app not overwritten', t => { + const args = {app: 'some-other-path'} + const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') + t.deepEqual(signOpts, {app: 'out', platform: 'darwin', version: 'version'}) + }) + + test('osxSign argument test: platform not overwritten', t => { + const args = {platform: 'mas'} + const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') + t.deepEqual(signOpts, {app: 'out', platform: 'darwin', version: 'version'}) + }) + + test('osxSign argument test: binaries not set', t => { + const args = {binaries: ['binary1', 'binary2']} + const signOpts = mac.createSignOpts(args, 'darwin', 'out', 'version') + t.deepEqual(signOpts, {app: 'out', platform: 'darwin', version: 'version'}) + }) + + darwinTest('codesign test', (t, opts) => { + opts.osxSign = {identity: 'Developer CodeCert'} + + let appPath + + return packager(opts) + .then(paths => { + appPath = path.join(paths[0], opts.name + '.app') + return fs.stat(appPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The expected .app directory should exist') + return exec(`codesign -v ${appPath}`) + }).then( + (stdout, stderr) => t.pass('codesign should verify successfully'), + err => { + const notFound = err && err.code === 127 + + if (notFound) { + console.log('codesign not installed; skipped') + } else { + throw err + } + } + ) + }) + + darwinTest('binary naming test', binaryNameTest) + darwinTest('sanitized binary naming test', binaryNameTest, {name: '@username/package-name'}, '@username-package-name') + darwinTest('executableName test', binaryNameTest, {executableName: 'app-name', name: 'MyAppName'}, 'app-name', 'MyAppName') + + darwinTest('CFBundleName is the sanitized app name and CFBundleDisplayName is the non-sanitized app name', (t, opts) => { + const appBundleIdentifier = 'com.electron.username-package-name' + const expectedSanitizedName = '@username-package-name' + + let plistPath + + opts.name = '@username/package-name' + + return packager(opts) + .then(paths => { + plistPath = path.join(paths[0], `${expectedSanitizedName}.app`, 'Contents', 'Info.plist') + return fs.stat(plistPath) + }).then(stats => { + t.true(stats.isFile(), 'The expected Info.plist file should exist') + return fs.readFile(plistPath, 'utf8') + }).then(file => { + const obj = plist.parse(file) + t.is(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string') + t.is(obj.CFBundleDisplayName, opts.name, 'CFBundleDisplayName should reflect opts.name') + t.is(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string') + t.is(obj.CFBundleName, expectedSanitizedName, 'CFBundleName should reflect a sanitized opts.name') + t.is(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string') + t.is(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') + return t.is(obj.CFBundleIdentifier, appBundleIdentifier, 'CFBundleIdentifier should reflect the sanitized opts.name') + }) + }) + + darwinTest('app and build version test', appVersionTest, '1.1.0', '1.1.0.1234') + darwinTest('app version test', appVersionTest, '1.1.0') + darwinTest('app and build version integer test', appVersionTest, 12, 1234) + darwinTest('infer app version from package.json test', (t, opts) => + packageAndParseInfoPlist(t, opts) + .then(obj => { + t.is(obj.CFBundleVersion, '4.99.101', 'CFBundleVersion should reflect package.json version') + return t.is(obj.CFBundleShortVersionString, '4.99.101', 'CFBundleShortVersionString should reflect package.json version') + }) + ) -util.packagerTest('binary naming test', createBinaryNameTest(baseOpts)) -util.packagerTest('sanitized binary naming test', createBinaryNameTest(Object.assign({}, baseOpts, {name: '@username/package-name'}), '@username-package-name')) -util.packagerTest('executableName test', createBinaryNameTest(Object.assign({}, baseOpts, {executableName: 'app-name', name: 'MyAppName'}), 'app-name', 'MyAppName')) + darwinTest('app categoryType test', (t, opts) => { + const appCategoryType = 'public.app-category.developer-tools' + opts.appCategoryType = appCategoryType -util.packagerTest('CFBundleName is the sanitized app name and CFBundleDisplayName is the non-sanitized app name', (t) => { - t.timeoutAfter(config.timeout) + return packageAndParseInfoPlist(t, opts) + .then(obj => t.is(obj.LSApplicationCategoryType, appCategoryType, 'LSApplicationCategoryType should reflect opts.appCategoryType')) + }) - let plistPath - const opts = Object.assign({}, baseOpts, {name: '@username/package-name'}) - const appBundleIdentifier = 'com.electron.username-package-name' - const expectedSanitizedName = '@username-package-name' + darwinTest('app bundle test', appBundleTest, 'com.electron.basetest') + darwinTest('app bundle (w/ special characters) test', appBundleTest, 'com.electron."bãśè tëßt!@#$%^&*()?\'') + darwinTest('app bundle app-bundle-id fallback test', appBundleTest) - packager(opts) - .then(paths => { - plistPath = path.join(paths[0], `${expectedSanitizedName}.app`, 'Contents', 'Info.plist') - return fs.stat(plistPath) - }).then(stats => { - t.true(stats.isFile(), 'The expected Info.plist file should exist') - return fs.readFile(plistPath, 'utf8') - }).then(file => { - const obj = plist.parse(file) - t.equal(typeof obj.CFBundleDisplayName, 'string', 'CFBundleDisplayName should be a string') - t.equal(obj.CFBundleDisplayName, opts.name, 'CFBundleDisplayName should reflect opts.name') - t.equal(typeof obj.CFBundleName, 'string', 'CFBundleName should be a string') - t.equal(obj.CFBundleName, expectedSanitizedName, 'CFBundleName should reflect a sanitized opts.name') - t.equal(typeof obj.CFBundleIdentifier, 'string', 'CFBundleIdentifier should be a string') - t.equal(/^[a-zA-Z0-9-.]*$/.test(obj.CFBundleIdentifier), true, 'CFBundleIdentifier should allow only alphanumeric (A-Z,a-z,0-9), hyphen (-), and period (.)') - t.equal(obj.CFBundleIdentifier, appBundleIdentifier, 'CFBundleIdentifier should reflect the sanitized opts.name') - return t.end() - }).catch(t.end) -}) - -util.packagerTest('app and build version test', createAppVersionTest(baseOpts, '1.1.0', '1.1.0.1234')) -util.packagerTest('infer app version from package.json test', createAppVersionInferenceTest(baseOpts)) -util.packagerTest('app version test', createAppVersionTest(baseOpts, '1.1.0')) -util.packagerTest('app and build version integer test', createAppVersionTest(baseOpts, 12, 1234)) + darwinTest('app bundle framework symlink test', (t, opts) => { + let frameworkPath -util.packagerTest('app categoryType test', createAppCategoryTypeTest(baseOpts, 'public.app-category.developer-tools')) + return packager(opts) + .then(paths => { + frameworkPath = path.join(paths[0], `${opts.name}.app`, 'Contents', 'Frameworks', 'Electron Framework.framework') + return fs.stat(frameworkPath) + }).then(stats => { + t.true(stats.isDirectory(), 'Expected Electron Framework.framework to be a directory') + return fs.lstat(path.join(frameworkPath, 'Electron Framework')) + }).then(stats => { + t.true(stats.isSymbolicLink(), 'Expected Electron Framework.framework/Electron Framework to be a symlink') + return fs.lstat(path.join(frameworkPath, 'Versions', 'Current')) + }).then(stats => t.true(stats.isSymbolicLink(), 'Expected Electron Framework.framework/Versions/Current to be a symlink')) + }) -util.packagerTest('app bundle test', createAppBundleTest(baseOpts, 'com.electron.basetest')) -util.packagerTest('app bundle (w/ special characters) test', createAppBundleTest(baseOpts, 'com.electron."bãśè tëßt!@#$%^&*()?\'')) -util.packagerTest('app bundle app-bundle-id fallback test', createAppBundleTest(baseOpts)) -util.packagerTest('app bundle framework symlink test', createAppBundleFrameworkTest(baseOpts)) + darwinTest('app helpers bundle test', appHelpersBundleTest, 'com.electron.basetest.helper') + darwinTest('app helpers bundle (w/ special characters) test', appHelpersBundleTest, 'com.electron."bãśè tëßt!@#$%^&*()?\'.hęłpėr') + darwinTest('app helpers bundle helper-bundle-id fallback to app-bundle-id test', appHelpersBundleTest, null, 'com.electron.basetest') + darwinTest('app helpers bundle helper-bundle-id fallback to app-bundle-id (w/ special characters) test', appHelpersBundleTest, null, 'com.electron."bãśè tëßt!!@#$%^&*()?\'') + darwinTest('app helpers bundle helper-bundle-id & app-bundle-id fallback test', appHelpersBundleTest) -util.packagerTest('app helpers bundle test', createAppHelpersBundleTest(baseOpts, 'com.electron.basetest.helper')) -util.packagerTest('app helpers bundle (w/ special characters) test', createAppHelpersBundleTest(baseOpts, 'com.electron."bãśè tëßt!@#$%^&*()?\'.hęłpėr')) -util.packagerTest('app helpers bundle helper-bundle-id fallback to app-bundle-id test', createAppHelpersBundleTest(baseOpts, null, 'com.electron.basetest')) -util.packagerTest('app helpers bundle helper-bundle-id fallback to app-bundle-id (w/ special characters) test', createAppHelpersBundleTest(baseOpts, null, 'com.electron."bãśè tëßt!!@#$%^&*()?\'')) -util.packagerTest('app helpers bundle helper-bundle-id & app-bundle-id fallback test', createAppHelpersBundleTest(baseOpts)) + darwinTest('appCopyright/NSHumanReadableCopyright test', (t, baseOpts) => { + const copyright = 'Copyright © 2003–2015 Organization. All rights reserved.' + const opts = Object.assign({}, baseOpts, {appCopyright: copyright}) -util.packagerTest('app humanReadableCopyright test', createAppHumanReadableCopyrightTest(baseOpts, 'Copyright © 2003–2015 Organization. All rights reserved.')) + return packageAndParseInfoPlist(t, opts) + .then(info => t.is(info.NSHumanReadableCopyright, copyright, 'NSHumanReadableCopyright should reflect opts.appCopyright')) + }) -util.packagerTest('app named Electron packaged successfully', (t) => { - const opts = Object.assign({}, baseOpts, {name: 'Electron'}) - let appPath + darwinTest('app named Electron packaged successfully', (t, baseOpts) => { + const opts = Object.assign({}, baseOpts, {name: 'Electron'}) + let appPath - packager(opts) - .then(paths => { - appPath = path.join(paths[0], 'Electron.app') - return fs.stat(appPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The Electron.app folder exists') - return fs.stat(path.join(appPath, 'Contents', 'MacOS', 'Electron')) - }).then(stats => { - t.true(stats.isFile(), 'The Electron.app/Contents/MacOS/Electron binary exists') - return t.end() - }).catch(t.end) -}) + return packager(opts) + .then(paths => { + appPath = path.join(paths[0], 'Electron.app') + return fs.stat(appPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The Electron.app folder exists') + return fs.stat(path.join(appPath, 'Contents', 'MacOS', 'Electron')) + }).then(stats => t.true(stats.isFile(), 'The Electron.app/Contents/MacOS/Electron binary exists')) + }) +} diff --git a/test/hooks.js b/test/hooks.js index db312026..66e9bde1 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -2,37 +2,31 @@ const config = require('./config.json') const packager = require('..') -const util = require('./util') +const util = require('./_util') function createHookTest (hookName) { - util.packagerTest('platform=all test (one arch) (' + hookName + ' hook)', (t) => { - t.timeoutAfter(config.timeout * 2) // 2 packages will be built during this test + util.packagerTest('platform=all test (one arch) (' + hookName + ' hook)', (t, opts) => { + util.timeoutTest(2) // 2 packages will be built during this test - var hookCalled = false - var opts = { - name: 'basicTest', - dir: util.fixtureSubdir('basic'), - electronVersion: config.version, - arch: 'ia32', - platform: 'all' - } + let hookCalled = false + opts.dir = util.fixtureSubdir('basic') + opts.electronVersion = config.version + opts.arch = 'ia32' + opts.platform = 'all' - opts[hookName] = [function testHook (buildPath, electronVersion, platform, arch, callback) { + opts[hookName] = [(buildPath, electronVersion, platform, arch, callback) => { hookCalled = true - t.equal(electronVersion, opts.electronVersion, hookName + ' electronVersion should be the same as the options object') - t.equal(arch, opts.arch, hookName + ' arch should be the same as the options object') + t.is(electronVersion, opts.electronVersion, `${hookName} electronVersion should be the same as the options object`) + t.is(arch, opts.arch, `${hookName} arch should be the same as the options object`) callback() }] - packager(opts) + return packager(opts) .then(finalPaths => { - t.equal(finalPaths.length, 2, 'packager call should resolve with expected number of paths') + t.is(finalPaths.length, 2, 'packager call should resolve with expected number of paths') t.true(hookCalled, `${hookName} methods should have been called`) return util.verifyPackageExistence(finalPaths) - }).then(exists => { - t.true(exists, 'Packages should be generated for both 32-bit platforms') - return t.end() - }).catch(t.end) + }).then(exists => t.deepEqual(exists, [true, true], 'Packages should be generated for both 32-bit platforms')) }) } diff --git a/test/ignore.js b/test/ignore.js index 18bef749..e175506e 100644 --- a/test/ignore.js +++ b/test/ignore.js @@ -1,106 +1,87 @@ 'use strict' const common = require('../common') -const config = require('./config.json') const fs = require('fs-extra') const ignore = require('../ignore') const path = require('path') const packager = require('..') -const test = require('tape') -const util = require('./util') - -function createIgnoreTest (opts, ignorePattern, ignoredFile) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'basicTest' - opts.dir = util.fixtureSubdir('basic') - if (ignorePattern) { - opts.ignore = ignorePattern - } - - let appPath - - packager(opts) - .then(paths => { - appPath = path.join(paths[0], util.generateResourcesPath(opts), 'app') - return fs.pathExists(path.join(appPath, 'package.json')) - }).then(exists => { - t.true(exists, 'The expected output directory should exist and contain files') - return fs.pathExists(path.join(appPath, ignoredFile)) - }).then(exists => { - t.false(exists, 'Ignored file should not exist in output app directory') - return t.end() - }).catch(t.end) +const test = require('ava') +const util = require('./_util') + +function ignoreTest (t, opts, ignorePattern, ignoredFile) { + util.timeoutTest() + + opts.name = 'ignoreTest' + opts.dir = util.fixtureSubdir('basic') + if (ignorePattern) { + opts.ignore = ignorePattern } + + let appPath + + return packager(opts) + .then(paths => { + appPath = path.join(paths[0], util.generateResourcesPath(opts), 'app') + return fs.pathExists(path.join(appPath, 'package.json')) + }).then(exists => { + t.true(exists, 'The expected output directory should exist and contain files') + return fs.pathExists(path.join(appPath, ignoredFile)) + }).then(exists => t.false(exists, 'Ignored file should not exist in output app directory')) } -function createIgnoreOutDirTest (opts, distPath) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'basicTest' - - var appDir = util.getWorkCwd() - opts.dir = appDir - // we don't use path.join here to avoid normalizing - var outDir = opts.dir + path.sep + distPath - opts.out = outDir - - fs.copy(util.fixtureSubdir('basic'), appDir, { - dereference: true, - stopOnErr: true, - filter: file => { return path.basename(file) !== 'node_modules' } - }).then(() => { - // create out dir before packager (real world issue - when second run includes unignored out dir) - return fs.mkdirp(outDir) - }).then(() => { - // create file to ensure that directory will be not ignored because empty - return fs.open(path.join(outDir, 'ignoreMe'), 'w') - }).then(fd => fs.close(fd)) - .then(() => packager(opts)) - .then(() => fs.pathExists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', path.basename(outDir)))) - .then(exists => { - t.false(exists, 'Out dir must not exist in output app directory') - return t.end() - }).catch(t.end) - } +function ignoreOutDirTest (t, opts, distPath) { + util.timeoutTest() + + opts.name = 'ignoreOutDirTest' + opts.dir = t.context.workDir + + // we don't use path.join here to avoid normalizing + var outDir = opts.dir + path.sep + distPath + opts.out = outDir + + return fs.copy(util.fixtureSubdir('basic'), t.context.workDir, { + dereference: true, + stopOnErr: true, + filter: file => { return path.basename(file) !== 'node_modules' } + }).then(() => + // create out dir before packager (real world issue - when second run includes unignored out dir) + fs.mkdirp(outDir) + ).then(() => + // create file to ensure that directory will be not ignored because empty + fs.open(path.join(outDir, 'ignoreMe'), 'w') + ).then(fd => fs.close(fd)) + .then(() => packager(opts)) + .then(() => fs.pathExists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', path.basename(outDir)))) + .then(exists => t.false(exists, 'Out dir must not exist in output app directory')) } -function createIgnoreImplicitOutDirTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - - opts.name = 'basicTest' - - var appDir = util.getWorkCwd() - opts.dir = appDir - var outDir = opts.dir - - var testFilename = 'ignoreMe' - var previousPackedResultDir - - fs.copy(util.fixtureSubdir('basic'), appDir, { - dereference: true, - stopOnErr: true, - filter: file => { return path.basename(file) !== 'node_modules' } - }).then(() => { - previousPackedResultDir = path.join(outDir, `${common.sanitizeAppName(opts.name)}-linux-ia32`) - return fs.mkdirp(previousPackedResultDir) - }).then(() => { - // create file to ensure that directory will be not ignored because empty - return fs.open(path.join(previousPackedResultDir, testFilename), 'w') - }).then(fd => fs.close(fd)) - .then(() => packager(opts)) - .then(() => fs.pathExists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', testFilename))) - .then(exists => { - t.false(exists, 'Out dir must not exist in output app directory') - return t.end() - }).catch(t.end) - } +function ignoreImplicitOutDirTest (t, opts) { + util.timeoutTest() + + opts.name = 'ignoreImplicitOutDirTest' + opts.dir = t.context.workDir + delete opts.out + + const testFilename = 'ignoreMe' + let previousPackedResultDir + + return fs.copy(util.fixtureSubdir('basic'), t.context.workDir, { + dereference: true, + stopOnErr: true, + filter: file => { return path.basename(file) !== 'node_modules' } + }).then(() => { + previousPackedResultDir = path.join(opts.dir, `${common.sanitizeAppName(opts.name)}-linux-ia32`) + return fs.mkdirp(previousPackedResultDir) + }).then(() => + // create file to ensure that directory will be not ignored because empty + fs.open(path.join(previousPackedResultDir, testFilename), 'w') + ).then(fd => fs.close(fd)) + .then(() => packager(opts)) + .then(() => fs.pathExists(path.join(opts.dir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', testFilename))) + .then(exists => t.false(exists, 'Out dir must not exist in output app directory')) } -test('generateIgnores ignores the generated temporary directory only on Linux', (t) => { +test('generateIgnores ignores the generated temporary directory only on Linux', t => { const tmpdir = '/foo/bar' const expected = path.join(tmpdir, 'electron-packager') let opts = {tmpdir} @@ -109,33 +90,30 @@ test('generateIgnores ignores the generated temporary directory only on Linux', // Array.prototype.includes is added (not behind a feature flag) in Node 6 if (process.platform === 'linux') { - t.notOk(opts.ignore.indexOf(expected) === -1, 'temporary dir in opts.ignore') + t.false(opts.ignore.indexOf(expected) === -1, 'temporary dir in opts.ignore') } else { - t.ok(opts.ignore.indexOf(expected) === -1, 'temporary dir not in opts.ignore') + t.true(opts.ignore.indexOf(expected) === -1, 'temporary dir not in opts.ignore') } - - t.end() }) test('generateOutIgnores ignores all possible platform/arch permutations', (t) => { - let ignores = ignore.generateOutIgnores({name: 'test'}) - t.equal(ignores.length, util.allPlatformArchCombosCount) - t.end() + const ignores = ignore.generateOutIgnores({name: 'test'}) + t.is(ignores.length, util.allPlatformArchCombosCount) }) -util.testSinglePlatform('ignore default test: .o files', createIgnoreTest, null, 'ignore.o') -util.testSinglePlatform('ignore default test: .obj files', createIgnoreTest, null, 'ignore.obj') -util.testSinglePlatform('ignore test: string in array', createIgnoreTest, ['ignorethis'], +util.testSinglePlatform('ignore default test: .o files', ignoreTest, null, 'ignore.o') +util.testSinglePlatform('ignore default test: .obj files', ignoreTest, null, 'ignore.obj') +util.testSinglePlatform('ignore test: string in array', ignoreTest, ['ignorethis'], 'ignorethis.txt') -util.testSinglePlatform('ignore test: string', createIgnoreTest, 'ignorethis', 'ignorethis.txt') -util.testSinglePlatform('ignore test: RegExp', createIgnoreTest, /ignorethis/, 'ignorethis.txt') -util.testSinglePlatform('ignore test: Function', createIgnoreTest, - file => { return file.match(/ignorethis/) }, 'ignorethis.txt') -util.testSinglePlatform('ignore test: string with slash', createIgnoreTest, 'ignore/this', +util.testSinglePlatform('ignore test: string', ignoreTest, 'ignorethis', 'ignorethis.txt') +util.testSinglePlatform('ignore test: RegExp', ignoreTest, /ignorethis/, 'ignorethis.txt') +util.testSinglePlatform('ignore test: Function', ignoreTest, + file => file.match(/ignorethis/), 'ignorethis.txt') +util.testSinglePlatform('ignore test: string with slash', ignoreTest, 'ignore/this', path.join('ignore', 'this.txt')) -util.testSinglePlatform('ignore test: only match subfolder of app', createIgnoreTest, +util.testSinglePlatform('ignore test: only match subfolder of app', ignoreTest, 'electron-packager', path.join('electron-packager', 'readme.txt')) -util.testSinglePlatform('ignore out dir test', createIgnoreOutDirTest, 'ignoredOutDir') -util.testSinglePlatform('ignore out dir test: unnormalized path', createIgnoreOutDirTest, +util.testSinglePlatform('ignore out dir test', ignoreOutDirTest, 'ignoredOutDir') +util.testSinglePlatform('ignore out dir test: unnormalized path', ignoreOutDirTest, './ignoredOutDir') -util.testSinglePlatform('ignore out dir test: unnormalized path', createIgnoreImplicitOutDirTest) +util.testSinglePlatform('ignore out dir test: implicit path', ignoreImplicitOutDirTest) diff --git a/test/index.js b/test/index.js deleted file mode 100644 index 99b5c23b..00000000 --- a/test/index.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict' - -const config = require('./config.json') -const exec = require('mz/child_process').exec -const util = require('./util') - -// Download all Electron distributions before running tests to avoid timing out due to network -// speed. Most tests run with the config.json version, but we have some tests using 0.37.4, and an -// electron module specific test using 1.3.1. -function preDownloadElectron () { - const versions = [ - config.version, - '0.37.4', - '1.3.1' - ] - return Promise.all(versions.map(util.downloadAll)) -} - -function npmInstallForFixture (fixture) { - console.log(`Running npm install in fixtures/${fixture}...`) - return exec('npm install --no-bin-links', {cwd: util.fixtureSubdir(fixture)}) - .catch((err) => console.error(err)) -} - -function npmInstallForFixtures () { - const fixtures = [ - 'basic', - 'basic-renamed-to-electron', - 'infer-missing-version-only', - 'el-0374' - ] - return Promise.all(fixtures.map(npmInstallForFixture)) -} - -preDownloadElectron() - .then(npmInstallForFixtures) - .then(() => { - console.log('Running tests...') - require('./basic') - require('./asar') - require('./cli') - require('./ignore') - require('./infer') - require('./hooks') - require('./prune') - require('./targets') - require('./win32') - - if (process.platform !== 'win32') { - // Perform additional tests specific to building for OS X - require('./darwin') - require('./mas') - } - - return true - }).catch((error) => { - console.error(error.stack || error) - return process.exit(1) - }) diff --git a/test/infer.js b/test/infer.js index 77ec19fa..14256a01 100644 --- a/test/infer.js +++ b/test/infer.js @@ -1,37 +1,30 @@ 'use strict' -const config = require('./config.json') const fs = require('fs-extra') const getMetadataFromPackageJSON = require('../infer') -const os = require('os') const packager = require('..') const path = require('path') const pkgUp = require('pkg-up') -const util = require('./util') +const util = require('./_util') -function createInferElectronVersionTest (fixture, packageName) { - return (opts) => { - return (t) => { - t.timeoutAfter(config.timeout) +function inferElectronVersionTest (t, opts, fixture, packageName) { + util.timeoutTest() - // Don't specify name or version - delete opts.electronVersion - opts.dir = path.join(__dirname, 'fixtures', fixture) - - getMetadataFromPackageJSON([], opts, opts.dir) - .then(() => { - const packageJSON = require(path.join(opts.dir, 'package.json')) - t.equal(opts.electronVersion, packageJSON.devDependencies[packageName], `The version should be inferred from installed ${packageName} version`) - return t.end() - }).catch(t.end) - } - } + // Don't specify name or version + delete opts.electronVersion + opts.dir = util.fixtureSubdir(fixture) + + return getMetadataFromPackageJSON([], opts, opts.dir) + .then(() => { + const packageJSON = require(path.join(opts.dir, 'package.json')) + return t.is(opts.electronVersion, packageJSON.devDependencies[packageName], `The version should be inferred from installed ${packageName} version`) + }) } -function copyFixtureToTempDir (fixtureSubdir) { - let tmpdir = path.join(os.tmpdir(), fixtureSubdir) - let fixtureDir = path.join(__dirname, 'fixtures', fixtureSubdir) - let tmpdirPkg = pkgUp.sync(path.join(tmpdir, '..')) +function copyFixtureToTempDir (t, fixtureSubdir) { + const tmpdir = path.join(t.context.tempDir, fixtureSubdir) + const fixtureDir = util.fixtureSubdir(fixtureSubdir) + const tmpdirPkg = pkgUp.sync(path.join(tmpdir, '..')) if (tmpdirPkg) { throw new Error(`Found package.json in parent of temp directory, which will interfere with test results. Please remove package.json at ${tmpdirPkg}`) @@ -42,62 +35,50 @@ function copyFixtureToTempDir (fixtureSubdir) { .then(() => tmpdir) } -function createInferFailureTest (opts, fixtureSubdir) { - return (t) => { - t.timeoutAfter(config.timeout) - - copyFixtureToTempDir(fixtureSubdir) - .then((dir) => { - delete opts.electronVersion - opts.dir = dir - - return packager(opts) - }).then( - paths => t.end('expected error'), - err => { - t.ok(err, 'error thrown') - return t.end() - } - ).catch((err) => { console.error('ERROR OMG', err); t.end() }) - } +function inferFailureTest (t, opts, fixtureSubdir) { + util.timeoutTest() + + return copyFixtureToTempDir(t, fixtureSubdir) + .then(dir => { + delete opts.electronVersion + opts.dir = dir + + return t.throws(packager(opts)) + }) } -function createInferMissingVersionTest (opts) { - return (t) => { - t.timeoutAfter(config.timeout) - copyFixtureToTempDir('infer-missing-version-only') - .then((dir) => { - delete opts.electronVersion - opts.dir = dir - - return getMetadataFromPackageJSON([], opts, dir) - }).then(() => { - const packageJSON = require(path.join(opts.dir, 'package.json')) - t.equal(opts.electronVersion, packageJSON.devDependencies['electron'], 'The version should be inferred from installed electron module version') - return t.end() - }).catch(t.end) - } +function inferMissingVersionTest (t, opts) { + util.timeoutTest() + + return copyFixtureToTempDir(t, 'infer-missing-version-only') + .then(dir => { + delete opts.electronVersion + opts.dir = dir + + return getMetadataFromPackageJSON([], opts, dir) + }).then(() => { + const packageJSON = require(path.join(opts.dir, 'package.json')) + return t.is(opts.electronVersion, packageJSON.devDependencies['electron'], 'The version should be inferred from installed electron module version') + }) } function testInferWin32metadata (t, opts, expected, assertionMessage) { - t.timeoutAfter(config.timeout) - copyFixtureToTempDir('infer-win32metadata') - .then((dir) => { + util.timeoutTest() + + return copyFixtureToTempDir(t, 'infer-win32metadata') + .then(dir => { opts.dir = dir return getMetadataFromPackageJSON(['win32'], opts, dir) - }).then(() => { - t.deepEqual(opts.win32metadata, expected, assertionMessage) - return t.end() - }).catch(t.end) + }).then(() => t.deepEqual(opts.win32metadata, expected, assertionMessage)) } function testInferWin32metadataAuthorObject (t, opts, author, expected, assertionMessage) { let packageJSONFilename - t.timeoutAfter(config.timeout) + util.timeoutTest() - copyFixtureToTempDir('infer-win32metadata') - .then((dir) => { + return copyFixtureToTempDir(t, 'infer-win32metadata') + .then(dir => { opts.dir = dir packageJSONFilename = path.join(dir, 'package.json') @@ -105,71 +86,43 @@ function testInferWin32metadataAuthorObject (t, opts, author, expected, assertio }).then(packageJSON => { packageJSON.author = author return fs.writeJson(packageJSONFilename, packageJSON) - }).then(() => { - return getMetadataFromPackageJSON(['win32'], opts, opts.dir) - }).then(() => { - t.deepEqual(opts.win32metadata, expected, assertionMessage) - return t.end() - }).catch(t.end) -} - -function createInferMissingFieldsTest (opts) { - return createInferFailureTest(opts, 'infer-missing-fields') -} - -function createInferWithBadFieldsTest (opts) { - return createInferFailureTest(opts, 'infer-bad-fields') + }).then(() => getMetadataFromPackageJSON(['win32'], opts, opts.dir)) + .then(() => t.deepEqual(opts.win32metadata, expected, assertionMessage)) } -function createInferWithMalformedJSONTest (opts) { - return createInferFailureTest(opts, 'infer-malformed-json') -} +util.testSinglePlatform('infer using `electron-prebuilt` package', inferElectronVersionTest, 'basic', 'electron-prebuilt') +util.testSinglePlatform('infer using `electron-prebuilt-compile` package', inferElectronVersionTest, 'infer-electron-prebuilt-compile', 'electron-prebuilt-compile') +util.testSinglePlatform('infer using `electron` package only', inferMissingVersionTest) +util.testSinglePlatform('infer where `electron` version is preferred over `electron-prebuilt`', inferElectronVersionTest, 'basic-renamed-to-electron', 'electron') +util.testSinglePlatform('infer win32metadata', (t, opts) => { + const expected = {CompanyName: 'Foo Bar'} -function createInferNonSpecificElectronPrebuiltCompileFailureTest (opts) { - return createInferFailureTest(opts, 'infer-non-specific-electron-prebuilt-compile') -} - -util.testSinglePlatform('infer using `electron-prebuilt` package', createInferElectronVersionTest('basic', 'electron-prebuilt')) -util.testSinglePlatform('infer using `electron-prebuilt-compile` package', createInferElectronVersionTest('infer-electron-prebuilt-compile', 'electron-prebuilt-compile')) -util.testSinglePlatform('infer using `electron` package only', createInferMissingVersionTest) -util.testSinglePlatform('infer where `electron` version is preferred over `electron-prebuilt`', createInferElectronVersionTest('basic-renamed-to-electron', 'electron')) -util.testSinglePlatform('infer win32metadata', (opts) => { - return (t) => { - const expected = {CompanyName: 'Foo Bar'} - - testInferWin32metadata(t, opts, expected, 'win32metadata matches package.json values') - } + return testInferWin32metadata(t, opts, expected, 'win32metadata matches package.json values') }) -util.testSinglePlatform('do not infer win32metadata if it already exists', (opts) => { - return (t) => { - opts.win32metadata = {CompanyName: 'Existing'} - const expected = Object.assign({}, opts.win32metadata) +util.testSinglePlatform('do not infer win32metadata if it already exists', (t, opts) => { + opts.win32metadata = {CompanyName: 'Existing'} + const expected = Object.assign({}, opts.win32metadata) - testInferWin32metadata(t, opts, expected, 'win32metadata did not update with package.json values') - } + return testInferWin32metadata(t, opts, expected, 'win32metadata did not update with package.json values') }) -util.testSinglePlatform('infer win32metadata when author is an object', (opts) => { - return (t) => { - const author = { - name: 'Foo Bar Object', - email: 'foobar@example.com' - } - const expected = {CompanyName: 'Foo Bar Object'} - - testInferWin32metadataAuthorObject(t, opts, author, expected, 'win32metadata did not update with package.json values') +util.testSinglePlatform('infer win32metadata when author is an object', (t, opts) => { + const author = { + name: 'Foo Bar Object', + email: 'foobar@example.com' } + const expected = {CompanyName: 'Foo Bar Object'} + + return testInferWin32metadataAuthorObject(t, opts, author, expected, 'win32metadata did not update with package.json values') }) -util.testSinglePlatform('do not infer win32metadata.CompanyName when author is an object without a name', (opts) => { - return (t) => { - const author = { - email: 'foobar@example.com' - } - const expected = {} - - testInferWin32metadataAuthorObject(t, opts, author, expected, 'win32metadata.CompanyName should not have been inferred') +util.testSinglePlatform('do not infer win32metadata.CompanyName when author is an object without a name', (t, opts) => { + const author = { + email: 'foobar@example.com' } + const expected = {} + + return testInferWin32metadataAuthorObject(t, opts, author, expected, 'win32metadata.CompanyName should not have been inferred') }) -util.testSinglePlatform('infer missing fields test', createInferMissingFieldsTest) -util.testSinglePlatform('infer with bad fields test', createInferWithBadFieldsTest) -util.testSinglePlatform('infer with malformed JSON test', createInferWithMalformedJSONTest) -util.testSinglePlatform('infer using a non-specific `electron-prebuilt-compile` package version', createInferNonSpecificElectronPrebuiltCompileFailureTest) +util.testSinglePlatform('infer missing fields test', inferFailureTest, 'infer-missing-fields') +util.testSinglePlatform('infer with bad fields test', inferFailureTest, 'infer-bad-fields') +util.testSinglePlatform('infer with malformed JSON test', inferFailureTest, 'infer-malformed-json') +util.testSinglePlatform('infer using a non-specific `electron-prebuilt-compile` package version', inferFailureTest, 'infer-non-specific-electron-prebuilt-compile') diff --git a/test/mas.js b/test/mas.js index aef2cb45..f6e25c78 100644 --- a/test/mas.js +++ b/test/mas.js @@ -2,30 +2,31 @@ const config = require('./config.json') const packager = require('..') -const util = require('./util') +const util = require('./_util') -const masOpts = { - name: 'basicTest', - dir: util.fixtureSubdir('basic'), - electronVersion: config.version, - arch: 'x64', - platform: 'mas' -} +if (!(process.env.CI && process.platform === 'win32')) { + const masOpts = { + name: 'masTest', + dir: util.fixtureSubdir('basic'), + electronVersion: config.version, + arch: 'x64', + platform: 'mas' + } -util.packagerTest('warn if building for mas and not signing', t => { - const warningLog = console.warn - let output = '' - console.warn = message => { output += message } + util.packagerTest('warn if building for mas and not signing', (t, baseOpts) => { + const warningLog = console.warn + let output = '' + console.warn = message => { output += message } - const finalize = err => { - console.warn = warningLog - t.end(err) - } + const finalize = err => { + console.warn = warningLog + if (err) throw err + } - packager(masOpts) - .then(() => { - t.ok(output.match(/signing is required for mas builds/), 'the correct warning is emitted') - return null - }).then(finalize) - .catch(finalize) -}) + return packager(Object.assign({}, baseOpts, masOpts)) + .then(() => + t.truthy(output.match(/signing is required for mas builds/), 'the correct warning is emitted') + ).then(finalize) + .catch(finalize) + }) +} diff --git a/test/prune.js b/test/prune.js index 6b945bdc..69225f58 100644 --- a/test/prune.js +++ b/test/prune.js @@ -1,91 +1,76 @@ 'use strict' -const config = require('./config.json') const fs = require('fs-extra') -const packager = require('..') const path = require('path') const prune = require('../prune') -const test = require('tape') -const util = require('./util') +const test = require('ava') +const util = require('./_util') const which = require('which') -function createPruneOptionTest (baseOpts, prune, testMessage) { - return (t) => { - t.timeoutAfter(config.timeout) +function createPruneOptionTest (t, baseOpts, prune, testMessage) { + util.timeoutTest() - let opts = Object.assign({}, baseOpts) - opts.name = 'basicTest' - opts.dir = path.join(__dirname, 'fixtures', 'basic') - opts.prune = prune + const opts = Object.assign({}, baseOpts, { + name: 'pruneTest', + dir: util.fixtureSubdir('basic'), + prune: prune + }) - let finalPath - let resourcesPath + let resourcesPath - packager(opts) - .then(paths => { - finalPath = paths[0] - return fs.stat(finalPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The expected output directory should exist') - resourcesPath = path.join(finalPath, util.generateResourcesPath(opts)) - return fs.stat(resourcesPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') - return fs.stat(path.join(resourcesPath, 'app', 'node_modules', 'run-series')) - }).then(stats => { - t.true(stats.isDirectory(), 'npm dependency should exist under app/node_modules') - return fs.pathExists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall')) - }).then(exists => { - t.equal(!prune, exists, testMessage) - return t.end() - }).catch(t.end) - } + return util.packageAndEnsureResourcesPath(t, opts) + .then(generatedResourcesPath => { + resourcesPath = generatedResourcesPath + return fs.stat(path.join(resourcesPath, 'app', 'node_modules', 'run-series')) + }).then(stats => { + t.true(stats.isDirectory(), 'npm dependency should exist under app/node_modules') + return fs.pathExists(path.join(resourcesPath, 'app', 'node_modules', 'run-waterfall')) + }).then(exists => t.is(!prune, exists, testMessage)) } -test('pruneCommand returns the correct command when passing a known package manager', (t) => { - t.equal(prune.pruneCommand('npm'), 'npm prune --production', 'passing npm gives the npm prune command') - t.equal(prune.pruneCommand('cnpm'), 'cnpm prune --production', 'passing cnpm gives the cnpm prune command') - t.equal(prune.pruneCommand('yarn'), 'yarn install --production --no-bin-links', 'passing yarn gives the yarn "prune command"') - t.end() +test('pruneCommand returns the correct command when passing a known package manager', t => { + t.is(prune.pruneCommand('npm'), 'npm prune --production', 'passing npm gives the npm prune command') + t.is(prune.pruneCommand('cnpm'), 'cnpm prune --production', 'passing cnpm gives the cnpm prune command') + t.is(prune.pruneCommand('yarn'), 'yarn install --production --no-bin-links', 'passing yarn gives the yarn "prune command"') }) -test('pruneCommand returns null when the package manager is unknown', (t) => { - t.notOk(prune.pruneCommand('unknown-package-manager')) - t.end() +test('pruneCommand returns undefined when the package manager is unknown', t => { + t.is(prune.pruneCommand('unknown-package-manager'), undefined) }) -util.testFailure('pruneModules returns an error when the package manager is unknown', () => - prune.pruneModules({packageManager: 'unknown-package-manager'}, '/tmp/app-path') +test('pruneModules returns an error when the package manager is unknown', t => + t.throws(prune.pruneModules({packageManager: 'unknown-package-manager'}, '/tmp/app-path')) ) if (process.platform === 'win32') { - util.testFailure('pruneModules returns an error when trying to use cnpm on Windows', () => - prune.pruneModules({packageManager: 'cnpm'}, '/tmp/app-path') + test('pruneModules returns an error when trying to use cnpm on Windows', t => + t.throws(prune.pruneModules({packageManager: 'cnpm'}, '/tmp/app-path')) ) } // This is not in the below loop so that it tests the default packageManager option. -util.testSinglePlatform('prune test with npm', (baseOpts) => { - return createPruneOptionTest(baseOpts, true, 'package.json devDependency should NOT exist under app/node_modules') +util.testSinglePlatform('prune test with npm', (t, baseOpts) => { + return createPruneOptionTest(t, baseOpts, true, 'package.json devDependency should NOT exist under app/node_modules') }) // Not in the loop because it doesn't depend on an executable -util.testSinglePlatform('prune test using pruner module (packageManager=false)', (baseOpts) => { +util.testSinglePlatform('prune test using pruner module (packageManager=false)', (t, baseOpts) => { const opts = Object.assign({packageManager: false}, baseOpts) - return createPruneOptionTest(opts, true, 'package.json devDependency should NOT exist under app/node_modules') + return createPruneOptionTest(t, opts, true, 'package.json devDependency should NOT exist under app/node_modules') }) for (const packageManager of ['cnpm', 'yarn']) { - which(packageManager, (err, resolvedPath) => { - if (err) return - - util.testSinglePlatform(`prune test with ${packageManager}`, (baseOpts) => { - const opts = Object.assign({packageManager: packageManager}, baseOpts) - return createPruneOptionTest(opts, true, 'package.json devDependency should NOT exist under app/node_modules') - }) - }) + try { + if (which.sync(packageManager)) { + util.testSinglePlatform(`prune test with ${packageManager}`, (t, baseOpts) => { + const opts = Object.assign({packageManager: packageManager}, baseOpts) + return createPruneOptionTest(t, opts, true, 'package.json devDependency should NOT exist under app/node_modules') + }) + } + } catch (e) { + console.log(`Cannot find ${packageManager}, skipping test`) + } } -util.testSinglePlatform('prune=false test', (baseOpts) => { - return createPruneOptionTest(baseOpts, false, 'npm devDependency should exist under app/node_modules') -}) +util.testSinglePlatform('prune=false test', createPruneOptionTest, false, + 'npm devDependency should exist under app/node_modules') diff --git a/test/targets.js b/test/targets.js index 27d59654..02140e64 100644 --- a/test/targets.js +++ b/test/targets.js @@ -2,26 +2,25 @@ const config = require('./config.json') const targets = require('../targets') -const test = require('tape') -const util = require('./util') +const test = require('ava') +const util = require('./_util') function createMultiTargetOptions (extraOpts) { return Object.assign({ - name: 'basicTest', + name: 'targetTest', dir: util.fixtureSubdir('basic'), electronVersion: config.version }, extraOpts) } function testMultiTarget (testcaseDescription, extraOpts, expectedPackageCount, packageExistenceMessage) { - test(testcaseDescription, (t) => { + test(testcaseDescription, t => { const opts = createMultiTargetOptions(extraOpts) const platforms = targets.validateListFromOptions(opts, 'platform') const archs = targets.validateListFromOptions(opts, 'arch') const combinations = targets.createPlatformArchPairs(opts, platforms, archs) - t.equal(combinations.length, expectedPackageCount, packageExistenceMessage) - t.end() + t.is(combinations.length, expectedPackageCount, packageExistenceMessage) }) } @@ -30,30 +29,26 @@ function testCombinations (testcaseDescription, arch, platform) { 'Packages should be generated for all combinations of specified archs and platforms') } -test('allOfficialArchsForPlatformAndVersion is undefined for unknown platforms', (t) => { - t.equal(targets.allOfficialArchsForPlatformAndVersion('unknown', '1.0.0'), undefined) - t.end() +test('allOfficialArchsForPlatformAndVersion is undefined for unknown platforms', t => { + t.is(targets.allOfficialArchsForPlatformAndVersion('unknown', '1.0.0'), undefined) }) -test('allOfficialArchsForPlatformAndVersion returns the correct arches for a known platform', (t) => { +test('allOfficialArchsForPlatformAndVersion returns the correct arches for a known platform', t => { t.deepEqual(targets.allOfficialArchsForPlatformAndVersion('darwin', '1.0.0'), ['x64']) - t.end() }) -test('allOfficialArchsForPlatformAndVersion returns arm64 when the correct version is specified', (t) => { - t.notEqual(targets.allOfficialArchsForPlatformAndVersion('linux', '1.8.0').indexOf('arm64'), -1, - 'should be found when version is >= 1.8.0') - t.equal(targets.allOfficialArchsForPlatformAndVersion('linux', '1.7.0').indexOf('arm64'), -1, - 'should not be found when version is < 1.8.0') - t.end() +test('allOfficialArchsForPlatformAndVersion returns arm64 when the correct version is specified', t => { + t.not(targets.allOfficialArchsForPlatformAndVersion('linux', '1.8.0').indexOf('arm64'), -1, + 'should be found when version is >= 1.8.0') + t.is(targets.allOfficialArchsForPlatformAndVersion('linux', '1.7.0').indexOf('arm64'), -1, + 'should not be found when version is < 1.8.0') }) -test('validateListFromOptions does not take non-Array/String values', (t) => { +test('validateListFromOptions does not take non-Array/String values', t => { targets.supported.digits = new Set(['64', '65']) - t.notOk(targets.validateListFromOptions({digits: 64}, 'digits') instanceof Array, + t.false(targets.validateListFromOptions({digits: 64}, 'digits') instanceof Array, 'should not be an Array') delete targets.supported.digits - t.end() }) testMultiTarget('build for all available official targets', {all: true, electronVersion: '1.8.0'}, @@ -72,11 +67,11 @@ testCombinations('multi-platform / multi-arch test, from arrays', ['ia32', 'x64' testCombinations('multi-platform / multi-arch test, from strings', 'ia32,x64', 'linux,win32') testCombinations('multi-platform / multi-arch test, from strings with spaces', 'ia32, x64', 'linux, win32') -util.packagerTest('fails with invalid arch', util.invalidOptionTest({ +test('fails with invalid arch', util.invalidOptionTest({ arch: 'z80', platform: 'linux' })) -util.packagerTest('fails with invalid platform', util.invalidOptionTest({ +test('fails with invalid platform', util.invalidOptionTest({ arch: 'ia32', platform: 'dos' })) diff --git a/test/win32.js b/test/win32.js index d77675e6..1f1b96af 100644 --- a/test/win32.js +++ b/test/win32.js @@ -4,11 +4,11 @@ const config = require('./config.json') const fs = require('fs-extra') const packager = require('..') const path = require('path') -const test = require('tape') -const util = require('./util') +const test = require('ava') +const util = require('./_util') const win32 = require('../win32') -const baseOpts = { +const win32Opts = { name: 'basicTest', dir: util.fixtureSubdir('basic'), electronVersion: config.version, @@ -21,10 +21,10 @@ function generateRceditOptionsSansIcon (opts) { } function generateVersionStringTest (metadataProperties, extraOpts, expectedValues, assertionMsgs) { - return (t) => { - t.timeoutAfter(config.timeout) + return t => { + util.timeoutTest() - const opts = Object.assign({}, baseOpts, extraOpts) + const opts = Object.assign({}, win32Opts, extraOpts) const rcOpts = generateRceditOptionsSansIcon(opts) metadataProperties = [].concat(metadataProperties) @@ -35,13 +35,12 @@ function generateVersionStringTest (metadataProperties, extraOpts, expectedValue const msg = assertionMsgs[i] if (property === 'version-string') { for (const subkey in value) { - t.equal(rcOpts[property][subkey], value[subkey], `${msg} (${subkey})`) + t.is(rcOpts[property][subkey], value[subkey], `${msg} (${subkey})`) } } else { - t.equal(rcOpts[property], value, msg) + t.is(rcOpts[property], value, msg) } }) - t.end() } } @@ -147,78 +146,65 @@ test('better error message when wine is not found', (t) => { err.code = 'ENOENT' err.syscall = 'spawn wine' - t.equal(err.message, 'spawn wine ENOENT') + t.is(err.message, 'spawn wine ENOENT') err = win32.updateWineMissingException(err) - t.notEqual(err.message, 'spawn wine ENOENT') - - t.end() + t.not(err.message, 'spawn wine ENOENT') }) -test('error message unchanged when error not about wine', (t) => { +test('error message unchanged when error not about wine', t => { let errNotEnoent = Error('unchanged') errNotEnoent.code = 'ESOMETHINGELSE' errNotEnoent.syscall = 'spawn wine' - t.equal(errNotEnoent.message, 'unchanged') + t.is(errNotEnoent.message, 'unchanged') errNotEnoent = win32.updateWineMissingException(errNotEnoent) - t.equal(errNotEnoent.message, 'unchanged') + t.is(errNotEnoent.message, 'unchanged') let errNotSpawnWine = Error('unchanged') errNotSpawnWine.code = 'ENOENT' errNotSpawnWine.syscall = 'spawn foo' - t.equal(errNotSpawnWine.message, 'unchanged') + t.is(errNotSpawnWine.message, 'unchanged') errNotSpawnWine = win32.updateWineMissingException(errNotSpawnWine) - t.equal(errNotSpawnWine.message, 'unchanged') - - t.end() + t.is(errNotSpawnWine.message, 'unchanged') }) -test('win32metadata defaults', (t) => { - const opts = { - name: 'Win32 App' - } +test('win32metadata defaults', t => { + const opts = { name: 'Win32 App' } const rcOpts = generateRceditOptionsSansIcon(opts) - t.equal(rcOpts['version-string'].FileDescription, opts.name, 'default FileDescription') - t.equal(rcOpts['version-string'].InternalName, opts.name, 'default InternalName') - t.equal(rcOpts['version-string'].OriginalFilename, 'Win32 App.exe', 'default OriginalFilename') - t.equal(rcOpts['version-string'].ProductName, opts.name, 'default ProductName') - t.end() + t.is(rcOpts['version-string'].FileDescription, opts.name, 'default FileDescription') + t.is(rcOpts['version-string'].InternalName, opts.name, 'default InternalName') + t.is(rcOpts['version-string'].OriginalFilename, 'Win32 App.exe', 'default OriginalFilename') + t.is(rcOpts['version-string'].ProductName, opts.name, 'default ProductName') }) -util.packagerTest('win32 executable name is based on sanitized app name', (t) => { - const opts = Object.assign({}, baseOpts, {name: '@username/package-name'}) +util.packagerTest('win32 executable name is based on sanitized app name', (t, opts) => { + Object.assign(opts, win32Opts, { name: '@username/package-name' }) - packager(opts) + return packager(opts) .then(paths => { - t.equal(1, paths.length, '1 bundle created') + t.is(1, paths.length, '1 bundle created') const appExePath = path.join(paths[0], '@username-package-name.exe') return fs.pathExists(appExePath) - }).then(exists => { - t.true(exists, 'The sanitized EXE filename should exist') - return t.end() - }).catch(t.end) + }).then(exists => t.true(exists, 'The sanitized EXE filename should exist')) }) -util.packagerTest('win32 executable name uses executableName when available', t => { - const opts = Object.assign({}, baseOpts, {name: 'PackageName', executableName: 'my-package'}) +util.packagerTest('win32 executable name uses executableName when available', (t, opts) => { + Object.assign(opts, win32Opts, { name: 'PackageName', executableName: 'my-package' }) - packager(opts) + return packager(opts) .then(paths => { - t.equal(1, paths.length, '1 bundle created') + t.is(1, paths.length, '1 bundle created') const appExePath = path.join(paths[0], 'my-package.exe') return fs.pathExists(appExePath) - }).then(exists => { - t.true(exists, 'the executableName-based filename should exist') - return t.end() - }).catch(t.end) + }).then(exists => t.true(exists, 'the executableName-based filename should exist')) }) -util.packagerTest('win32 build version sets FileVersion test', setFileVersionTest('2.3.4.5')) -util.packagerTest('win32 app version sets ProductVersion test', setProductVersionTest('5.4.3.2')) -util.packagerTest('win32 app copyright sets LegalCopyright test', setCopyrightTest('Copyright Bar')) -util.packagerTest('win32 set LegalCopyright and CompanyName test', setCopyrightAndCompanyNameTest('Copyright Bar', 'MyCompany LLC')) -util.packagerTest('win32 set CompanyName test', setCompanyNameTest('MyCompany LLC')) -util.packagerTest('win32 set requested-execution-level test', setRequestedExecutionLevelTest('asInvoker')) -util.packagerTest('win32 set application-manifest test', setApplicationManifestTest('/path/to/manifest.xml')) +test('win32 build version sets FileVersion test', setFileVersionTest('2.3.4.5')) +test('win32 app version sets ProductVersion test', setProductVersionTest('5.4.3.2')) +test('win32 app copyright sets LegalCopyright test', setCopyrightTest('Copyright Bar')) +test('win32 set LegalCopyright and CompanyName test', setCopyrightAndCompanyNameTest('Copyright Bar', 'MyCompany LLC')) +test('win32 set CompanyName test', setCompanyNameTest('MyCompany LLC')) +test('win32 set requested-execution-level test', setRequestedExecutionLevelTest('asInvoker')) +test('win32 set application-manifest test', setApplicationManifestTest('/path/to/manifest.xml')) From 7f87b6b5d35aff89984e6a082e8a65b0001783e9 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Sun, 3 Dec 2017 18:14:05 -0800 Subject: [PATCH 02/10] Run packager tests serially --- test/_util.js | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/test/_util.js b/test/_util.js index 73ca16ce..f7a57df3 100644 --- a/test/_util.js +++ b/test/_util.js @@ -13,6 +13,23 @@ const targets = require('../targets') const tempy = require('tempy') const test = require('ava') +function downloadAll (version) { + console.log(`Calling electron-download for ${version} before running tests...`) + const combinations = common.createDownloadCombos({electronVersion: config.version, all: true}, targets.officialPlatforms, targets.officialArchs, (platform, arch) => { + // Skip testing darwin/mas target on Windows since electron-packager itself skips it + // (see https://github.com/electron-userland/electron-packager/issues/71) + return common.isPlatformMac(platform) && process.platform === 'win32' + }) + + return Promise.all(combinations.map(combination => { + return common.downloadElectronZip(Object.assign({}, combination, { + cache: path.join(os.homedir(), '.electron'), + quiet: !!process.env.CI, + version: version + })) + })) +} + // Download all Electron distributions before running tests to avoid timing out due to network // speed. Most tests run with the config.json version, but we have some tests using 0.37.4, and an // electron module specific test using 1.3.1. @@ -22,13 +39,20 @@ function preDownloadElectron () { '0.37.4', '1.3.1' ] - return Promise.all(versions.map(exports.downloadAll)) + return Promise.all(versions.map(downloadAll)) } function npmInstallForFixture (fixture) { console.log(`Running npm install in fixtures/${fixture}...`) - return exec('npm install --no-bin-links', {cwd: exports.fixtureSubdir(fixture)}) - .catch((err) => console.error(err)) + const fixtureDir = exports.fixtureSubdir(fixture) + return fs.exists(path.join(fixtureDir, 'node_modules')) + .then(exists => { + if (exists) { + return true + } else { + return exec('npm install --no-bin-links', {cwd: fixtureDir}) + } + }) } function npmInstallForFixtures () { @@ -88,23 +112,6 @@ exports.areFilesEqual = function areFilesEqual (file1, file2) { }) } -exports.downloadAll = function downloadAll (version) { - console.log(`Calling electron-download for ${version} before running tests...`) - const combinations = common.createDownloadCombos({electronVersion: config.version, all: true}, targets.officialPlatforms, targets.officialArchs, (platform, arch) => { - // Skip testing darwin/mas target on Windows since electron-packager itself skips it - // (see https://github.com/electron-userland/electron-packager/issues/71) - return common.isPlatformMac(platform) && process.platform === 'win32' - }) - - return Promise.all(combinations.map(combination => { - return common.downloadElectronZip(Object.assign({}, combination, { - cache: path.join(os.homedir(), '.electron'), - quiet: !!process.env.CI, - version: version - })) - })) -} - exports.fixtureSubdir = function fixtureSubdir (subdir) { return path.join(__dirname, 'fixtures', subdir) } @@ -133,7 +140,7 @@ exports.packageAndEnsureResourcesPath = function packageAndEnsureResourcesPath ( } exports.packagerTest = function packagerTest (name, testFunction) { - test(name, t => { + test.serial(name, t => { const opts = { name: 'packagerTest', out: t.context.workDir, From 9337fc890137ae619555dc275cac6e1262bd66e1 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Sun, 3 Dec 2017 23:58:45 -0800 Subject: [PATCH 03/10] Readd test index, cleanup test timeouts --- package.json | 2 +- test/_util.js | 17 +++++++++++------ test/asar.js | 4 ++-- test/darwin.js | 6 ++---- test/hooks.js | 2 +- test/ignore.js | 6 +++--- test/index.js | 19 +++++++++++++++++++ test/infer.js | 10 +++++----- test/prune.js | 2 +- test/win32.js | 2 +- 10 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 test/index.js diff --git a/package.json b/package.json index ef040baa..c48bf5e6 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "scripts": { "coveralls": "nyc report --reporter=text-lcov | coveralls", "lint": "eslint .", - "test": "npm run lint && nyc ava test" + "test": "npm run lint && nyc ava test/index.js" }, "directories": { "test": "test" diff --git a/test/_util.js b/test/_util.js index f7a57df3..1e629f7c 100644 --- a/test/_util.js +++ b/test/_util.js @@ -43,13 +43,13 @@ function preDownloadElectron () { } function npmInstallForFixture (fixture) { - console.log(`Running npm install in fixtures/${fixture}...`) const fixtureDir = exports.fixtureSubdir(fixture) return fs.exists(path.join(fixtureDir, 'node_modules')) .then(exists => { if (exists) { return true } else { + console.log(`Running npm install in fixtures/${fixture}...`) return exec('npm install --no-bin-links', {cwd: fixtureDir}) } }) @@ -68,8 +68,10 @@ function npmInstallForFixtures () { const ORIGINAL_CWD = process.cwd() const WORK_CWD = path.join(__dirname, 'work') -function ensureWorkDirExists () { - return fs.mkdirs(WORK_CWD).then(() => process.chdir(WORK_CWD)) +function ensureEmptyWorkDirExists () { + return fs.remove(WORK_CWD) + .then(() => fs.mkdirs(WORK_CWD)) + .then(() => process.chdir(WORK_CWD)) } test.before(t => @@ -79,7 +81,7 @@ test.before(t => console.error(error.stack || error) return process.exit(1) }) - .then(ensureWorkDirExists) + .then(ensureEmptyWorkDirExists) ) test.after.always(t => { @@ -93,6 +95,9 @@ test.beforeEach(t => { }) test.afterEach.always(t => { + if (t.context.timeout) { + clearTimeout(t.context.timeout) + } return fs.remove(t.context.workDir) .then(() => fs.remove(t.context.tempDir)) }) @@ -159,10 +164,10 @@ exports.testSinglePlatform = function testSinglePlatform (name, testFunction /*, }) } -exports.timeoutTest = function timeoutTest (multiplier) { +exports.timeoutTest = function timeoutTest (t, multiplier) { if (!multiplier) multiplier = 1 - setTimeout(() => { throw new Error('Timed out') }, config.timeout * multiplier) + t.context.timeout = setTimeout(() => { throw new Error('Timed out') }, config.timeout * multiplier) } exports.verifyPackageExistence = function verifyPackageExistence (finalPaths) { diff --git a/test/asar.js b/test/asar.js index cced974f..21a769f3 100644 --- a/test/asar.js +++ b/test/asar.js @@ -20,7 +20,7 @@ test('asar argument test: asar is not an Object or a bool', t => { }) util.testSinglePlatform('default_app.asar removal test', (t, opts) => { - util.timeoutTest() + util.timeoutTest(t) opts.name = 'default_appASARTest' opts.dir = util.fixtureSubdir('el-0374') @@ -32,7 +32,7 @@ util.testSinglePlatform('default_app.asar removal test', (t, opts) => { }) util.testSinglePlatform('asar test', (t, opts) => { - util.timeoutTest() + util.timeoutTest(t) opts.name = 'asarTest' opts.dir = util.fixtureSubdir('basic') diff --git a/test/darwin.js b/test/darwin.js index 8feb64ef..79187fc5 100644 --- a/test/darwin.js +++ b/test/darwin.js @@ -28,7 +28,7 @@ function testWrapper (testName, extraOpts, testFunction/*, ...extraArgs */) { const extraArgs = Array.prototype.slice.call(arguments, 3) util.packagerTest(testName, (t, baseOpts) => { - util.timeoutTest(2) + util.timeoutTest(t, 2) const opts = Object.assign({}, baseOpts, extraOpts) return testFunction.apply(null, [t, opts].concat(extraArgs)) @@ -100,7 +100,7 @@ function iconTest (t, opts, icon, iconPath) { return util.packageAndEnsureResourcesPath(t, opts) .then(generatedResourcesPath => { resourcesPath = generatedResourcesPath - const outputPath = resourcesPath.replace(`${path.sep}${exports.generateResourcesPath(opts)}`, '') + const outputPath = resourcesPath.replace(`${path.sep}${util.generateResourcesPath(opts)}`, '') return parseInfoPlist(t, opts, outputPath) }).then(obj => { return util.areFilesEqual(iconPath, path.join(resourcesPath, obj.CFBundleIconFile)) @@ -108,8 +108,6 @@ function iconTest (t, opts, icon, iconPath) { } function extendInfoTest (t, baseOpts, extraPathOrParams) { - util.timeoutTest() - const opts = Object.assign({}, baseOpts, { appBundleId: 'com.electron.extratest', appCategoryType: 'public.app-category.music', diff --git a/test/hooks.js b/test/hooks.js index 66e9bde1..d98ccf4b 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -6,7 +6,7 @@ const util = require('./_util') function createHookTest (hookName) { util.packagerTest('platform=all test (one arch) (' + hookName + ' hook)', (t, opts) => { - util.timeoutTest(2) // 2 packages will be built during this test + util.timeoutTest(t, 2) // 2 packages will be built during this test let hookCalled = false opts.dir = util.fixtureSubdir('basic') diff --git a/test/ignore.js b/test/ignore.js index e175506e..86ead8c3 100644 --- a/test/ignore.js +++ b/test/ignore.js @@ -9,7 +9,7 @@ const test = require('ava') const util = require('./_util') function ignoreTest (t, opts, ignorePattern, ignoredFile) { - util.timeoutTest() + util.timeoutTest(t) opts.name = 'ignoreTest' opts.dir = util.fixtureSubdir('basic') @@ -30,7 +30,7 @@ function ignoreTest (t, opts, ignorePattern, ignoredFile) { } function ignoreOutDirTest (t, opts, distPath) { - util.timeoutTest() + util.timeoutTest(t) opts.name = 'ignoreOutDirTest' opts.dir = t.context.workDir @@ -56,7 +56,7 @@ function ignoreOutDirTest (t, opts, distPath) { } function ignoreImplicitOutDirTest (t, opts) { - util.timeoutTest() + util.timeoutTest(t) opts.name = 'ignoreImplicitOutDirTest' opts.dir = t.context.workDir diff --git a/test/index.js b/test/index.js new file mode 100644 index 00000000..77179633 --- /dev/null +++ b/test/index.js @@ -0,0 +1,19 @@ +'use strict' + +require('./_util') + +require('./basic') +require('./asar') +require('./cli') +require('./ignore') +require('./infer') +require('./hooks') +require('./prune') +require('./targets') +require('./win32') + +if (process.platform !== 'win32') { + // Perform additional tests specific to building for OS X + require('./darwin') + require('./mas') +} diff --git a/test/infer.js b/test/infer.js index 14256a01..18628baa 100644 --- a/test/infer.js +++ b/test/infer.js @@ -8,7 +8,7 @@ const pkgUp = require('pkg-up') const util = require('./_util') function inferElectronVersionTest (t, opts, fixture, packageName) { - util.timeoutTest() + util.timeoutTest(t) // Don't specify name or version delete opts.electronVersion @@ -36,7 +36,7 @@ function copyFixtureToTempDir (t, fixtureSubdir) { } function inferFailureTest (t, opts, fixtureSubdir) { - util.timeoutTest() + util.timeoutTest(t) return copyFixtureToTempDir(t, fixtureSubdir) .then(dir => { @@ -48,7 +48,7 @@ function inferFailureTest (t, opts, fixtureSubdir) { } function inferMissingVersionTest (t, opts) { - util.timeoutTest() + util.timeoutTest(t) return copyFixtureToTempDir(t, 'infer-missing-version-only') .then(dir => { @@ -63,7 +63,7 @@ function inferMissingVersionTest (t, opts) { } function testInferWin32metadata (t, opts, expected, assertionMessage) { - util.timeoutTest() + util.timeoutTest(t) return copyFixtureToTempDir(t, 'infer-win32metadata') .then(dir => { @@ -75,7 +75,7 @@ function testInferWin32metadata (t, opts, expected, assertionMessage) { function testInferWin32metadataAuthorObject (t, opts, author, expected, assertionMessage) { let packageJSONFilename - util.timeoutTest() + util.timeoutTest(t) return copyFixtureToTempDir(t, 'infer-win32metadata') .then(dir => { diff --git a/test/prune.js b/test/prune.js index 69225f58..0324f7de 100644 --- a/test/prune.js +++ b/test/prune.js @@ -8,7 +8,7 @@ const util = require('./_util') const which = require('which') function createPruneOptionTest (t, baseOpts, prune, testMessage) { - util.timeoutTest() + util.timeoutTest(t) const opts = Object.assign({}, baseOpts, { name: 'pruneTest', diff --git a/test/win32.js b/test/win32.js index 1f1b96af..290b9228 100644 --- a/test/win32.js +++ b/test/win32.js @@ -22,7 +22,7 @@ function generateRceditOptionsSansIcon (opts) { function generateVersionStringTest (metadataProperties, extraOpts, expectedValues, assertionMsgs) { return t => { - util.timeoutTest() + util.timeoutTest(t) const opts = Object.assign({}, win32Opts, extraOpts) const rcOpts = generateRceditOptionsSansIcon(opts) From ede15897528bd567abcc0db40008f27f25b667e5 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Mon, 4 Dec 2017 18:21:37 -0800 Subject: [PATCH 04/10] Fix Linux-specific tests --- test/basic.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/basic.js b/test/basic.js index 4b9c4785..65a2344d 100644 --- a/test/basic.js +++ b/test/basic.js @@ -287,7 +287,7 @@ for (const platform of ['darwin', 'linux']) { util.testSinglePlatform(`extraResource test: array (${platform})`, createExtraResourceArrayTest, platform) } -util.packagerTest('building for Linux target sanitizes binary name', (t, opts) => { +util.testSinglePlatform('building for Linux target sanitizes binary name', (t, opts) => { opts.name = '@username/package-name' opts.dir = util.fixtureSubdir('basic') @@ -298,7 +298,7 @@ util.packagerTest('building for Linux target sanitizes binary name', (t, opts) = }).then(stats => t.true(stats.isFile(), 'The sanitized binary filename should exist')) }) -util.packagerTest('executableName honored when building for Linux target', (t, opts) => { +util.testSinglePlatform('executableName honored when building for Linux target', (t, opts) => { opts.name = 'PackageName' opts.executableName = 'my-package' opts.dir = util.fixtureSubdir('basic') @@ -321,7 +321,7 @@ util.packagerTest('fails with invalid version', util.invalidOptionTest({ } })) -util.packagerTest('dir argument test: should work with relative path', (t, opts) => { +util.testSinglePlatform('dir argument test: should work with relative path', (t, opts) => { opts.name = 'ElectronTest' opts.dir = path.join('..', 'fixtures', 'el-0374') opts.electronVersion = '0.37.4' From 0c946f268812d0b09dbf6c54cbd3264288faa69b Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 5 Dec 2017 19:52:37 -0800 Subject: [PATCH 05/10] Use the global timeout --- package.json | 3 +++ test/_util.js | 9 --------- test/asar.js | 4 ---- test/config.json | 1 - test/darwin.js | 1 - test/hooks.js | 3 +-- test/ignore.js | 6 ------ test/infer.js | 9 --------- test/prune.js | 2 -- test/win32.js | 2 -- 10 files changed, 4 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index c48bf5e6..b88cfe95 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,9 @@ "test": "test" }, "keywords": [], + "ava": { + "timeout": "60s" + }, "eslintConfig": { "extends": [ "plugin:ava/recommended", diff --git a/test/_util.js b/test/_util.js index 1e629f7c..54c76939 100644 --- a/test/_util.js +++ b/test/_util.js @@ -95,9 +95,6 @@ test.beforeEach(t => { }) test.afterEach.always(t => { - if (t.context.timeout) { - clearTimeout(t.context.timeout) - } return fs.remove(t.context.workDir) .then(() => fs.remove(t.context.tempDir)) }) @@ -164,12 +161,6 @@ exports.testSinglePlatform = function testSinglePlatform (name, testFunction /*, }) } -exports.timeoutTest = function timeoutTest (t, multiplier) { - if (!multiplier) multiplier = 1 - - t.context.timeout = setTimeout(() => { throw new Error('Timed out') }, config.timeout * multiplier) -} - exports.verifyPackageExistence = function verifyPackageExistence (finalPaths) { return Promise.all(finalPaths.map((finalPath) => { return fs.stat(finalPath) diff --git a/test/asar.js b/test/asar.js index 21a769f3..ec335394 100644 --- a/test/asar.js +++ b/test/asar.js @@ -20,8 +20,6 @@ test('asar argument test: asar is not an Object or a bool', t => { }) util.testSinglePlatform('default_app.asar removal test', (t, opts) => { - util.timeoutTest(t) - opts.name = 'default_appASARTest' opts.dir = util.fixtureSubdir('el-0374') opts.electronVersion = '0.37.4' @@ -32,8 +30,6 @@ util.testSinglePlatform('default_app.asar removal test', (t, opts) => { }) util.testSinglePlatform('asar test', (t, opts) => { - util.timeoutTest(t) - opts.name = 'asarTest' opts.dir = util.fixtureSubdir('basic') opts.asar = { diff --git a/test/config.json b/test/config.json index 7d6ada01..b8d7c26e 100644 --- a/test/config.json +++ b/test/config.json @@ -1,4 +1,3 @@ { - "timeout": 30000, "version": "0.35.6" } diff --git a/test/darwin.js b/test/darwin.js index 79187fc5..1b95b388 100644 --- a/test/darwin.js +++ b/test/darwin.js @@ -28,7 +28,6 @@ function testWrapper (testName, extraOpts, testFunction/*, ...extraArgs */) { const extraArgs = Array.prototype.slice.call(arguments, 3) util.packagerTest(testName, (t, baseOpts) => { - util.timeoutTest(t, 2) const opts = Object.assign({}, baseOpts, extraOpts) return testFunction.apply(null, [t, opts].concat(extraArgs)) diff --git a/test/hooks.js b/test/hooks.js index d98ccf4b..4b7303dc 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -5,9 +5,8 @@ const packager = require('..') const util = require('./_util') function createHookTest (hookName) { + // 2 packages will be built during this test util.packagerTest('platform=all test (one arch) (' + hookName + ' hook)', (t, opts) => { - util.timeoutTest(t, 2) // 2 packages will be built during this test - let hookCalled = false opts.dir = util.fixtureSubdir('basic') opts.electronVersion = config.version diff --git a/test/ignore.js b/test/ignore.js index 86ead8c3..0932c0dd 100644 --- a/test/ignore.js +++ b/test/ignore.js @@ -9,8 +9,6 @@ const test = require('ava') const util = require('./_util') function ignoreTest (t, opts, ignorePattern, ignoredFile) { - util.timeoutTest(t) - opts.name = 'ignoreTest' opts.dir = util.fixtureSubdir('basic') if (ignorePattern) { @@ -30,8 +28,6 @@ function ignoreTest (t, opts, ignorePattern, ignoredFile) { } function ignoreOutDirTest (t, opts, distPath) { - util.timeoutTest(t) - opts.name = 'ignoreOutDirTest' opts.dir = t.context.workDir @@ -56,8 +52,6 @@ function ignoreOutDirTest (t, opts, distPath) { } function ignoreImplicitOutDirTest (t, opts) { - util.timeoutTest(t) - opts.name = 'ignoreImplicitOutDirTest' opts.dir = t.context.workDir delete opts.out diff --git a/test/infer.js b/test/infer.js index 18628baa..7d3e5700 100644 --- a/test/infer.js +++ b/test/infer.js @@ -8,8 +8,6 @@ const pkgUp = require('pkg-up') const util = require('./_util') function inferElectronVersionTest (t, opts, fixture, packageName) { - util.timeoutTest(t) - // Don't specify name or version delete opts.electronVersion opts.dir = util.fixtureSubdir(fixture) @@ -36,8 +34,6 @@ function copyFixtureToTempDir (t, fixtureSubdir) { } function inferFailureTest (t, opts, fixtureSubdir) { - util.timeoutTest(t) - return copyFixtureToTempDir(t, fixtureSubdir) .then(dir => { delete opts.electronVersion @@ -48,8 +44,6 @@ function inferFailureTest (t, opts, fixtureSubdir) { } function inferMissingVersionTest (t, opts) { - util.timeoutTest(t) - return copyFixtureToTempDir(t, 'infer-missing-version-only') .then(dir => { delete opts.electronVersion @@ -63,8 +57,6 @@ function inferMissingVersionTest (t, opts) { } function testInferWin32metadata (t, opts, expected, assertionMessage) { - util.timeoutTest(t) - return copyFixtureToTempDir(t, 'infer-win32metadata') .then(dir => { opts.dir = dir @@ -75,7 +67,6 @@ function testInferWin32metadata (t, opts, expected, assertionMessage) { function testInferWin32metadataAuthorObject (t, opts, author, expected, assertionMessage) { let packageJSONFilename - util.timeoutTest(t) return copyFixtureToTempDir(t, 'infer-win32metadata') .then(dir => { diff --git a/test/prune.js b/test/prune.js index 0324f7de..7fd09fad 100644 --- a/test/prune.js +++ b/test/prune.js @@ -8,8 +8,6 @@ const util = require('./_util') const which = require('which') function createPruneOptionTest (t, baseOpts, prune, testMessage) { - util.timeoutTest(t) - const opts = Object.assign({}, baseOpts, { name: 'pruneTest', dir: util.fixtureSubdir('basic'), diff --git a/test/win32.js b/test/win32.js index 290b9228..716be0a6 100644 --- a/test/win32.js +++ b/test/win32.js @@ -22,8 +22,6 @@ function generateRceditOptionsSansIcon (opts) { function generateVersionStringTest (metadataProperties, extraOpts, expectedValues, assertionMsgs) { return t => { - util.timeoutTest(t) - const opts = Object.assign({}, win32Opts, extraOpts) const rcOpts = generateRceditOptionsSansIcon(opts) From e4cfda38f0ff6560ca9712816416fbb461011368 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 5 Dec 2017 19:53:00 -0800 Subject: [PATCH 06/10] Fix test description --- test/hooks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hooks.js b/test/hooks.js index 4b7303dc..91c159ae 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -6,7 +6,7 @@ const util = require('./_util') function createHookTest (hookName) { // 2 packages will be built during this test - util.packagerTest('platform=all test (one arch) (' + hookName + ' hook)', (t, opts) => { + util.packagerTest(`platform=all test (one arch) (${hookName} hook)`, (t, opts) => { let hookCalled = false opts.dir = util.fixtureSubdir('basic') opts.electronVersion = config.version From 5dce2ee08b761df3a9bdb75a3715026c0d04e86a Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Sun, 17 Dec 2017 22:40:05 -0800 Subject: [PATCH 07/10] Make sure name inferring is tested --- test/infer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/infer.js b/test/infer.js index 7d3e5700..6a1889ae 100644 --- a/test/infer.js +++ b/test/infer.js @@ -8,7 +8,6 @@ const pkgUp = require('pkg-up') const util = require('./_util') function inferElectronVersionTest (t, opts, fixture, packageName) { - // Don't specify name or version delete opts.electronVersion opts.dir = util.fixtureSubdir(fixture) @@ -36,6 +35,7 @@ function copyFixtureToTempDir (t, fixtureSubdir) { function inferFailureTest (t, opts, fixtureSubdir) { return copyFixtureToTempDir(t, fixtureSubdir) .then(dir => { + delete opts.name delete opts.electronVersion opts.dir = dir @@ -68,6 +68,8 @@ function testInferWin32metadata (t, opts, expected, assertionMessage) { function testInferWin32metadataAuthorObject (t, opts, author, expected, assertionMessage) { let packageJSONFilename + delete opts.name + return copyFixtureToTempDir(t, 'infer-win32metadata') .then(dir => { opts.dir = dir From bcbe02ce6acd90e6a364caa44bdae6f496d8e825 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 26 Dec 2017 14:40:39 -0800 Subject: [PATCH 08/10] Use module.exports --- test/_util.js | 132 ++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 69 deletions(-) diff --git a/test/_util.js b/test/_util.js index 54c76939..3b0fead2 100644 --- a/test/_util.js +++ b/test/_util.js @@ -43,7 +43,7 @@ function preDownloadElectron () { } function npmInstallForFixture (fixture) { - const fixtureDir = exports.fixtureSubdir(fixture) + const fixtureDir = module.exports.fixtureSubdir(fixture) return fs.exists(path.join(fixtureDir, 'node_modules')) .then(exists => { if (exists) { @@ -99,74 +99,68 @@ test.afterEach.always(t => { .then(() => fs.remove(t.context.tempDir)) }) -exports.allPlatformArchCombosCount = 8 - -exports.areFilesEqual = function areFilesEqual (file1, file2) { - let buffer1, buffer2 - - return fs.readFile(file1) - .then((data) => { - buffer1 = data - return fs.readFile(file2) - }).then((data) => { - buffer2 = data - return bufferEqual(buffer1, buffer2) +module.exports = { + allPlatformArchCombosCount: 8, + areFilesEqual: function areFilesEqual (file1, file2) { + let buffer1, buffer2 + + return fs.readFile(file1) + .then((data) => { + buffer1 = data + return fs.readFile(file2) + }).then((data) => { + buffer2 = data + return bufferEqual(buffer1, buffer2) + }) + }, + fixtureSubdir: function fixtureSubdir (subdir) { + return path.join(__dirname, 'fixtures', subdir) + }, + generateResourcesPath: function generateResourcesPath (opts) { + return common.isPlatformMac(opts.platform) + ? path.join(opts.name + '.app', 'Contents', 'Resources') + : 'resources' + }, + invalidOptionTest: function invalidOptionTest (opts) { + return t => t.throws(packager(opts)) + }, + packageAndEnsureResourcesPath: function packageAndEnsureResourcesPath (t, opts) { + let resourcesPath + + return packager(opts) + .then(paths => { + resourcesPath = path.join(paths[0], module.exports.generateResourcesPath(opts)) + return fs.stat(resourcesPath) + }).then(stats => { + t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') + return resourcesPath + }) + }, + packagerTest: function packagerTest (name, testFunction) { + test.serial(name, t => { + const opts = { + name: 'packagerTest', + out: t.context.workDir, + tmpdir: t.context.tempDir + } + return testFunction(t, opts) }) -} - -exports.fixtureSubdir = function fixtureSubdir (subdir) { - return path.join(__dirname, 'fixtures', subdir) -} - -exports.generateResourcesPath = function generateResourcesPath (opts) { - return common.isPlatformMac(opts.platform) - ? path.join(opts.name + '.app', 'Contents', 'Resources') - : 'resources' -} - -exports.invalidOptionTest = function invalidOptionTest (opts) { - return t => t.throws(packager(opts)) -} - -exports.packageAndEnsureResourcesPath = function packageAndEnsureResourcesPath (t, opts) { - let resourcesPath - - return packager(opts) - .then(paths => { - resourcesPath = path.join(paths[0], exports.generateResourcesPath(opts)) - return fs.stat(resourcesPath) - }).then(stats => { - t.true(stats.isDirectory(), 'The output directory should contain the expected resources subdirectory') - return resourcesPath + }, + // Rest parameters are added (not behind a feature flag) in Node 6 + testSinglePlatform: function testSinglePlatform (name, testFunction /*, ...testFunctionArgs */) { + const args = Array.prototype.slice.call(arguments, 2) + module.exports.packagerTest(name, (t, opts) => { + Object.assign(opts, {platform: 'linux', arch: 'x64', electronVersion: config.version}) + return testFunction.apply(null, [t, opts].concat(args)) }) -} - -exports.packagerTest = function packagerTest (name, testFunction) { - test.serial(name, t => { - const opts = { - name: 'packagerTest', - out: t.context.workDir, - tmpdir: t.context.tempDir - } - return testFunction(t, opts) - }) -} - -// Rest parameters are added (not behind a feature flag) in Node 6 -exports.testSinglePlatform = function testSinglePlatform (name, testFunction /*, ...testFunctionArgs */) { - const args = Array.prototype.slice.call(arguments, 2) - exports.packagerTest(name, (t, opts) => { - Object.assign(opts, {platform: 'linux', arch: 'x64', electronVersion: config.version}) - return testFunction.apply(null, [t, opts].concat(args)) - }) -} - -exports.verifyPackageExistence = function verifyPackageExistence (finalPaths) { - return Promise.all(finalPaths.map((finalPath) => { - return fs.stat(finalPath) - .then( - stats => stats.isDirectory(), - () => false - ) - })) + }, + verifyPackageExistence: function verifyPackageExistence (finalPaths) { + return Promise.all(finalPaths.map((finalPath) => { + return fs.stat(finalPath) + .then( + stats => stats.isDirectory(), + () => false + ) + })) + } } From 363f63761ae7c5b3cc3e6d86e1d04ce813903775 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 26 Dec 2017 15:06:54 -0800 Subject: [PATCH 09/10] Infer tests can be parallelized --- test/_util.js | 38 +++++++++++++++++++++++++++----------- test/infer.js | 24 ++++++++++++------------ 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/test/_util.js b/test/_util.js index 3b0fead2..90fb3718 100644 --- a/test/_util.js +++ b/test/_util.js @@ -99,6 +99,13 @@ test.afterEach.always(t => { .then(() => fs.remove(t.context.tempDir)) }) +function testSinglePlatform (name, testFunction, testFunctionArgs, parallel) { + module.exports.packagerTest(name, (t, opts) => { + Object.assign(opts, module.exports.singlePlatformOptions()) + return testFunction.apply(null, [t, opts].concat(testFunctionArgs)) + }, parallel) +} + module.exports = { allPlatformArchCombosCount: 8, areFilesEqual: function areFilesEqual (file1, file2) { @@ -136,23 +143,32 @@ module.exports = { return resourcesPath }) }, - packagerTest: function packagerTest (name, testFunction) { - test.serial(name, t => { - const opts = { + packagerTest: function packagerTest (name, testFunction, parallel) { + const testDefinition = parallel ? test : test.serial + testDefinition(name, t => { + return testFunction(t, { name: 'packagerTest', out: t.context.workDir, tmpdir: t.context.tempDir - } - return testFunction(t, opts) + }) }) }, + singlePlatformOptions: function singlePlatformOptions () { + return { + platform: 'linux', + arch: 'x64', + electronVersion: config.version + } + }, // Rest parameters are added (not behind a feature flag) in Node 6 - testSinglePlatform: function testSinglePlatform (name, testFunction /*, ...testFunctionArgs */) { - const args = Array.prototype.slice.call(arguments, 2) - module.exports.packagerTest(name, (t, opts) => { - Object.assign(opts, {platform: 'linux', arch: 'x64', electronVersion: config.version}) - return testFunction.apply(null, [t, opts].concat(args)) - }) + testSinglePlatform: function (name, testFunction /*, ...testFunctionArgs */) { + const testFunctionArgs = Array.prototype.slice.call(arguments, 2) + return testSinglePlatform(name, testFunction, testFunctionArgs, false) + }, + // Rest parameters are added (not behind a feature flag) in Node 6 + testSinglePlatformParallel: function (name, testFunction /*, ...testFunctionArgs */) { + const testFunctionArgs = Array.prototype.slice.call(arguments, 2) + return testSinglePlatform(name, testFunction, testFunctionArgs, true) }, verifyPackageExistence: function verifyPackageExistence (finalPaths) { return Promise.all(finalPaths.map((finalPath) => { diff --git a/test/infer.js b/test/infer.js index 6a1889ae..93e57789 100644 --- a/test/infer.js +++ b/test/infer.js @@ -83,22 +83,22 @@ function testInferWin32metadataAuthorObject (t, opts, author, expected, assertio .then(() => t.deepEqual(opts.win32metadata, expected, assertionMessage)) } -util.testSinglePlatform('infer using `electron-prebuilt` package', inferElectronVersionTest, 'basic', 'electron-prebuilt') -util.testSinglePlatform('infer using `electron-prebuilt-compile` package', inferElectronVersionTest, 'infer-electron-prebuilt-compile', 'electron-prebuilt-compile') -util.testSinglePlatform('infer using `electron` package only', inferMissingVersionTest) -util.testSinglePlatform('infer where `electron` version is preferred over `electron-prebuilt`', inferElectronVersionTest, 'basic-renamed-to-electron', 'electron') -util.testSinglePlatform('infer win32metadata', (t, opts) => { +util.testSinglePlatformParallel('infer using `electron-prebuilt` package', inferElectronVersionTest, 'basic', 'electron-prebuilt') +util.testSinglePlatformParallel('infer using `electron-prebuilt-compile` package', inferElectronVersionTest, 'infer-electron-prebuilt-compile', 'electron-prebuilt-compile') +util.testSinglePlatformParallel('infer using `electron` package only', inferMissingVersionTest) +util.testSinglePlatformParallel('infer where `electron` version is preferred over `electron-prebuilt`', inferElectronVersionTest, 'basic-renamed-to-electron', 'electron') +util.testSinglePlatformParallel('infer win32metadata', (t, opts) => { const expected = {CompanyName: 'Foo Bar'} return testInferWin32metadata(t, opts, expected, 'win32metadata matches package.json values') }) -util.testSinglePlatform('do not infer win32metadata if it already exists', (t, opts) => { +util.testSinglePlatformParallel('do not infer win32metadata if it already exists', (t, opts) => { opts.win32metadata = {CompanyName: 'Existing'} const expected = Object.assign({}, opts.win32metadata) return testInferWin32metadata(t, opts, expected, 'win32metadata did not update with package.json values') }) -util.testSinglePlatform('infer win32metadata when author is an object', (t, opts) => { +util.testSinglePlatformParallel('infer win32metadata when author is an object', (t, opts) => { const author = { name: 'Foo Bar Object', email: 'foobar@example.com' @@ -107,7 +107,7 @@ util.testSinglePlatform('infer win32metadata when author is an object', (t, opts return testInferWin32metadataAuthorObject(t, opts, author, expected, 'win32metadata did not update with package.json values') }) -util.testSinglePlatform('do not infer win32metadata.CompanyName when author is an object without a name', (t, opts) => { +util.testSinglePlatformParallel('do not infer win32metadata.CompanyName when author is an object without a name', (t, opts) => { const author = { email: 'foobar@example.com' } @@ -115,7 +115,7 @@ util.testSinglePlatform('do not infer win32metadata.CompanyName when author is a return testInferWin32metadataAuthorObject(t, opts, author, expected, 'win32metadata.CompanyName should not have been inferred') }) -util.testSinglePlatform('infer missing fields test', inferFailureTest, 'infer-missing-fields') -util.testSinglePlatform('infer with bad fields test', inferFailureTest, 'infer-bad-fields') -util.testSinglePlatform('infer with malformed JSON test', inferFailureTest, 'infer-malformed-json') -util.testSinglePlatform('infer using a non-specific `electron-prebuilt-compile` package version', inferFailureTest, 'infer-non-specific-electron-prebuilt-compile') +util.testSinglePlatformParallel('infer missing fields test', inferFailureTest, 'infer-missing-fields') +util.testSinglePlatformParallel('infer with bad fields test', inferFailureTest, 'infer-bad-fields') +util.testSinglePlatformParallel('infer with malformed JSON test', inferFailureTest, 'infer-malformed-json') +util.testSinglePlatformParallel('infer using a non-specific `electron-prebuilt-compile` package version', inferFailureTest, 'infer-non-specific-electron-prebuilt-compile') From e266525ced63ba094f8740fcc7f6bbb2713fdec1 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Mon, 1 Jan 2018 12:23:03 -0800 Subject: [PATCH 10/10] Move testsuite setup outside of AVA for CI --- .travis.yml | 1 + test/_setup.js | 86 +++++++++++++++++++++++++++++++++++++++ test/_util.js | 85 +++++--------------------------------- test/ci/_before_script.js | 5 +++ test/ci/appveyor.yml | 1 + 5 files changed, 103 insertions(+), 75 deletions(-) create mode 100644 test/_setup.js create mode 100755 test/ci/_before_script.js diff --git a/.travis.yml b/.travis.yml index 537fc1d2..1948bc6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ before_install: test/ci/before_install.sh install: - npm install - npm update +before_script: test/ci/_before_script.js after_success: npm run coveralls branches: only: diff --git a/test/_setup.js b/test/_setup.js new file mode 100644 index 00000000..2e979242 --- /dev/null +++ b/test/_setup.js @@ -0,0 +1,86 @@ +'use strict' + +const common = require('../common') +const config = require('./config.json') +const exec = require('mz/child_process').exec +const fs = require('fs-extra') +const os = require('os') +const path = require('path') +const targets = require('../targets') + +function fixtureSubdir (subdir) { + return path.join(__dirname, 'fixtures', subdir) +} + +function downloadAll (version) { + console.log(`Calling electron-download for ${version} before running tests...`) + const combinations = common.createDownloadCombos({electronVersion: config.version, all: true}, targets.officialPlatforms, targets.officialArchs, (platform, arch) => { + // Skip testing darwin/mas target on Windows since electron-packager itself skips it + // (see https://github.com/electron-userland/electron-packager/issues/71) + return common.isPlatformMac(platform) && process.platform === 'win32' + }) + + return Promise.all(combinations.map(combination => { + return common.downloadElectronZip(Object.assign({}, combination, { + cache: path.join(os.homedir(), '.electron'), + quiet: !!process.env.CI, + version: version + })) + })) +} + +// Download all Electron distributions before running tests to avoid timing out due to network +// speed. Most tests run with the config.json version, but we have some tests using 0.37.4, and an +// electron module specific test using 1.3.1. +function preDownloadElectron () { + const versions = [ + config.version, + '0.37.4', + '1.3.1' + ] + return Promise.all(versions.map(downloadAll)) +} + +function npmInstallForFixture (fixture) { + const fixtureDir = fixtureSubdir(fixture) + return fs.exists(path.join(fixtureDir, 'node_modules')) + .then(exists => { + if (exists) { + return true + } else { + console.log(`Running npm install in fixtures/${fixture}...`) + return exec('npm install --no-bin-links', {cwd: fixtureDir}) + } + }) +} + +function npmInstallForFixtures () { + const fixtures = [ + 'basic', + 'basic-renamed-to-electron', + 'infer-missing-version-only', + 'el-0374' + ] + return Promise.all(fixtures.map(npmInstallForFixture)) +} + +const WORK_CWD = path.join(__dirname, 'work') + +function ensureEmptyWorkDirExists () { + return fs.remove(WORK_CWD) + .then(() => fs.mkdirs(WORK_CWD)) +} + +module.exports = { + fixtureSubdir: fixtureSubdir, + setupTestsuite: function setupTestsuite () { + return preDownloadElectron() + .then(npmInstallForFixtures) + .catch(error => { + console.error(error.stack || error) + return process.exit(1) + }) + .then(ensureEmptyWorkDirExists) + }, + WORK_CWD: WORK_CWD +} diff --git a/test/_util.js b/test/_util.js index 90fb3718..04c8bf79 100644 --- a/test/_util.js +++ b/test/_util.js @@ -4,89 +4,26 @@ const bufferEqual = require('buffer-equal') const common = require('../common') const config = require('./config.json') -const exec = require('mz/child_process').exec const fs = require('fs-extra') -const os = require('os') const packager = require('../index') const path = require('path') -const targets = require('../targets') +const setup = require('./_setup') const tempy = require('tempy') const test = require('ava') -function downloadAll (version) { - console.log(`Calling electron-download for ${version} before running tests...`) - const combinations = common.createDownloadCombos({electronVersion: config.version, all: true}, targets.officialPlatforms, targets.officialArchs, (platform, arch) => { - // Skip testing darwin/mas target on Windows since electron-packager itself skips it - // (see https://github.com/electron-userland/electron-packager/issues/71) - return common.isPlatformMac(platform) && process.platform === 'win32' - }) - - return Promise.all(combinations.map(combination => { - return common.downloadElectronZip(Object.assign({}, combination, { - cache: path.join(os.homedir(), '.electron'), - quiet: !!process.env.CI, - version: version - })) - })) -} - -// Download all Electron distributions before running tests to avoid timing out due to network -// speed. Most tests run with the config.json version, but we have some tests using 0.37.4, and an -// electron module specific test using 1.3.1. -function preDownloadElectron () { - const versions = [ - config.version, - '0.37.4', - '1.3.1' - ] - return Promise.all(versions.map(downloadAll)) -} - -function npmInstallForFixture (fixture) { - const fixtureDir = module.exports.fixtureSubdir(fixture) - return fs.exists(path.join(fixtureDir, 'node_modules')) - .then(exists => { - if (exists) { - return true - } else { - console.log(`Running npm install in fixtures/${fixture}...`) - return exec('npm install --no-bin-links', {cwd: fixtureDir}) - } - }) -} - -function npmInstallForFixtures () { - const fixtures = [ - 'basic', - 'basic-renamed-to-electron', - 'infer-missing-version-only', - 'el-0374' - ] - return Promise.all(fixtures.map(npmInstallForFixture)) -} - const ORIGINAL_CWD = process.cwd() -const WORK_CWD = path.join(__dirname, 'work') - -function ensureEmptyWorkDirExists () { - return fs.remove(WORK_CWD) - .then(() => fs.mkdirs(WORK_CWD)) - .then(() => process.chdir(WORK_CWD)) -} -test.before(t => - preDownloadElectron() - .then(npmInstallForFixtures) - .catch(error => { - console.error(error.stack || error) - return process.exit(1) - }) - .then(ensureEmptyWorkDirExists) -) +test.before(t => { + if (!process.env.CI) { + return setup.setupTestsuite() + .then(() => process.chdir(setup.WORK_CWD)) + } + return Promise.resolve(process.chdir(setup.WORK_CWD)) +}) test.after.always(t => { process.chdir(ORIGINAL_CWD) - return fs.remove(WORK_CWD) + return fs.remove(setup.WORK_CWD) }) test.beforeEach(t => { @@ -120,9 +57,7 @@ module.exports = { return bufferEqual(buffer1, buffer2) }) }, - fixtureSubdir: function fixtureSubdir (subdir) { - return path.join(__dirname, 'fixtures', subdir) - }, + fixtureSubdir: setup.fixtureSubdir, generateResourcesPath: function generateResourcesPath (opts) { return common.isPlatformMac(opts.platform) ? path.join(opts.name + '.app', 'Contents', 'Resources') diff --git a/test/ci/_before_script.js b/test/ci/_before_script.js new file mode 100755 index 00000000..a14db1bb --- /dev/null +++ b/test/ci/_before_script.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +'use strict' + +require('../_setup').setupTestsuite() diff --git a/test/ci/appveyor.yml b/test/ci/appveyor.yml index da8df386..c0ed2b7d 100644 --- a/test/ci/appveyor.yml +++ b/test/ci/appveyor.yml @@ -27,6 +27,7 @@ install: test_script: - node --version - npm --version +- node test/ci/_before_script.js - npm test build: off