addons-linter/tests/integration/run-as-production-env.js

156 строки
4.0 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const chalk = require('chalk');
const gunzip = require('gunzip-maybe');
const tar = require('tar-fs');
const tmp = require('tmp-promise');
const baseSpawnOptions = { shell: true };
// Get the npm script to run.
const npmScript = process.argv[2];
// Get the path to the test dir to run.
const jestTestsPath = process.argv[3];
if (!npmScript) {
console.error(chalk.red('Missing mandatory npm script to run'));
process.exit(1);
}
if (!jestTestsPath) {
console.error(chalk.red('Missing mandatory path to the tests dir to run'));
process.exit(1);
}
// Cleanup the temporary even if non empty.
tmp.setGracefulCleanup();
function spawnWithShell(cmd, args, options) {
return spawn(cmd, args, { ...baseSpawnOptions, ...options });
}
function getPackedName() {
return new Promise((resolve, reject) => {
fs.readFile('package.json', (err, data) => {
if (err) {
reject(err);
} else {
const info = JSON.parse(data.toString());
resolve(`${info.name}-${info.version}.tgz`);
}
});
});
}
function createPackage(tmpDirPath) {
console.log(chalk.green('Create a pre-release npm package archive'));
return new Promise((resolve, reject) => {
const pkgPack = spawnWithShell('npm', ['pack', process.cwd()], {
cwd: tmpDirPath,
});
pkgPack.stdout.pipe(process.stdout);
pkgPack.stderr.pipe(process.stderr);
pkgPack.on('close', (exitCode) => {
if (exitCode === 0) {
resolve(
getPackedName().then((filename) => {
return path.join(tmpDirPath, filename);
})
);
} else {
reject(new Error('Failed to create npm package archive'));
}
});
});
}
function unpackTarPackage(packagePath, destDir) {
console.log(
chalk.green(['Unpacking', packagePath, 'package into', destDir].join(' '))
);
return new Promise((resolve, reject) => {
fs.createReadStream(packagePath)
.pipe(gunzip())
.pipe(tar.extract(destDir))
.on('error', reject)
.on('finish', resolve);
});
}
function installPackageDeps(packageDir) {
console.log(chalk.green('Install production package dependencies'));
return new Promise((resolve, reject) => {
const pkgInstall = spawnWithShell(
'npm',
['install', '--production', '--no-lockfile'],
{
cwd: packageDir,
}
);
pkgInstall.stdout.pipe(process.stdout);
pkgInstall.stderr.pipe(process.stderr);
pkgInstall.on('close', (exitCode) => {
if (exitCode === 0) {
resolve();
} else {
reject(new Error('Failed to install package dependencies'));
}
});
});
}
function runIntegrationTests(packageDir) {
console.log(
chalk.green('Running integration tests in production-like environent')
);
return new Promise((resolve, reject) => {
const testRun = spawnWithShell(
'npm',
['run', npmScript, '--', jestTestsPath],
{
env: {
...process.env,
PATH: process.env.PATH,
TEST_BIN_PATH: path.join(packageDir, 'bin'),
},
}
);
testRun.stdout.pipe(process.stdout);
testRun.stderr.pipe(process.stderr);
testRun.on('close', (exitCode) => {
if (exitCode === 0) {
resolve();
} else {
reject(new Error('Failed to run integration tests'));
}
});
});
}
// Create a production-like environment in a temporarily created directory
// and then run the integration tests on it.
tmp
.withDir(
(tmpDir) => {
const tmpDirPath = tmpDir.path;
const unpackedDirPath = path.join(tmpDirPath, 'package');
return createPackage(tmpDirPath)
.then((archiveFilePath) =>
unpackTarPackage(archiveFilePath, tmpDirPath)
)
.then(() => installPackageDeps(unpackedDirPath))
.then(() => runIntegrationTests(unpackedDirPath));
},
{ unsafeCleanup: true }
)
.catch((err) => {
console.error(err.stack ? chalk.red(err.stack) : chalk.red(err));
process.exit(1);
});