Files
react/scripts/fiber/record-tests
Ben Alpert 64cba04bf9 Build infra for tracking dev-specific failures (#8228)
I'll plan to change all of our console.error and component-tree expects to expectDev. It's a little annoying that we need to make sure tests don't throw (see my change to normalizeCodeLocInfo) but any alternative would seem to require two separate test runs or a much more cumbersome syntax.
2016-11-13 14:00:07 -08:00

181 lines
5.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict';
const child_process = require('child_process');
const crypto = require('crypto');
const fs = require('fs');
const os = require('os');
const path = require('path');
const SearchSource = require('jest').SearchSource;
const TestRunner = require('jest').TestRunner;
const createHasteContext = require('jest-runtime').createHasteContext;
const readConfig = require('jest-config').readConfig;
const argv = {};
const root = path.normalize(path.join(__dirname, '..', '..'));
const testPathPattern = '';
function wrapRunnerFile(runnerPath) {
const filename = path.join(
os.tmpdir(),
'test-runner-' + crypto.randomBytes(8).toString('hex') + '.js'
);
fs.writeFileSync(
filename,
`
'use strict';
var runnerPath = ${JSON.stringify(runnerPath)};
var wrap = require(${JSON.stringify(__filename)}).wrapRunner;
module.exports = wrap(runnerPath);
`
);
return filename;
}
function wrapRunner(originalPath) {
const original = require(originalPath);
// Assuming originalPath is .../jest-jasmine2/build/index.js
const JasmineReporter = require(
path.join(path.dirname(originalPath), 'reporter.js')
);
// For each spec, we store whether there was any expectDev() failure. This
// relies on the results being returned in the same order as they are run.
const hadDevFailures = [];
let environment;
const oldSpecStarted = JasmineReporter.prototype.specStarted;
JasmineReporter.prototype.specStarted = function(result) {
oldSpecStarted.apply(this, arguments);
environment.global.__suppressDevFailures = true;
environment.global.__hadDevFailures = false;
};
const oldSpecDone = JasmineReporter.prototype.specDone;
JasmineReporter.prototype.specDone = function(result) {
oldSpecDone.apply(this, arguments);
environment.global.__suppressDevFailures = false;
hadDevFailures.push(environment.global.__hadDevFailures);
};
return function runner(config, env, runtime, testPath) {
environment = env;
return original(config, env, runtime, testPath)
.then((results) => {
results.failureMessage = null;
hadDevFailures.forEach((hadFailures, i) => {
results.testResults[i].hadDevFailures = hadFailures;
});
hadDevFailures.length = 0;
return results;
});
};
}
function runJest() {
return readConfig(argv, root)
.then((config) => {
config = Object.assign({}, config, {
testRunner: wrapRunnerFile(config.testRunner),
});
return createHasteContext(config, {}).then((hasteMap) => {
const source = new SearchSource(hasteMap, config);
return source.getTestPaths({testPathPattern})
.then((data) => {
const runner = new TestRunner(
hasteMap,
config,
{
maxWorkers: Math.max(os.cpus().length - 1, 1),
getTestSummary: () => 'You did it!'
}
);
return runner.runTests(data.paths);
});
});
});
}
function formatResults(runResults, predicate) {
const formatted = [];
runResults.testResults.forEach((fileResult) => {
const file = path.relative(root, fileResult.testFilePath);
const tests = fileResult.testResults.filter(
(test) => predicate(fileResult, test)
);
if (tests.length) {
const lines = [file].concat(tests.map((test) => '* ' + test.title));
formatted.push(lines.join('\n'));
}
});
formatted.sort();
return formatted.join('\n\n');
}
function recordTests(trackFacts) {
process.env.REACT_DOM_JEST_USE_FIBER = true;
runJest()
.then((runResults) => {
const passing = formatResults(
runResults,
(file, test) => test.status === 'passed' && !test.hadDevFailures
);
const passingExceptDev = formatResults(
runResults,
(file, test) => test.status === 'passed' && test.hadDevFailures
);
const failing = formatResults(
runResults,
(file, test) => test.status === 'failed'
);
fs.writeFileSync(
path.join(__dirname, 'tests-passing.txt'),
passing + '\n'
);
fs.writeFileSync(
path.join(__dirname, 'tests-passing-except-dev.txt'),
passingExceptDev + '\n'
);
fs.writeFileSync(
path.join(__dirname, 'tests-failing.txt'),
failing + '\n'
);
if (trackFacts) {
const fact = runResults.numPassedTests + '/' + runResults.numTotalTests;
// TODO: Shelling out here is silly.
child_process.spawnSync(
process.execPath,
[
path.join(__dirname, '../facts-tracker/index.js'),
'fiber-tests',
fact,
],
{
stdio: 'inherit',
}
);
}
});
}
if (require.main === module) {
const argv = require('yargs')
.demand(0, 0)
.boolean('track-facts')
.describe('track-facts', 'Use facts-tracker to record passing tests.')
.strict()
.help()
.argv;
recordTests(argv.trackFacts);
}
module.exports = {
wrapRunner,
};