#!/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 TestWatcher = require('jest').TestWatcher; const createContext = require('jest-runtime').createContext; const readConfig = require('jest-config').readConfig; const root = path.normalize(path.join(__dirname, '..', '..')); const argv = { config: path.join(root, 'scripts/jest/fiber.config.json'), }; 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(globalConfig, config, env, runtime, testPath) { environment = env; return original(globalConfig, 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(maxWorkers) { let { config } = readConfig(argv, root); config = Object.assign({}, config, { testRunner: wrapRunnerFile(config.testRunner), maxWorkers: maxWorkers, }); return createContext(config, {}).then((context) => { const source = new SearchSource(context); return source.getTestPaths({testPathPattern}) .then((data) => { const runner = new TestRunner( config, { getTestSummary: () => 'You did it!' } ); const watcher = new TestWatcher({isWatchMode: false}); return runner.runTests(data.tests, watcher).catch(x => { console.log('error', x); }); }); }); } function formatResults(runResults, predicate) { const formatted = []; runResults.testResults.forEach((fileResult) => { const filePath = path.relative(root, fileResult.testFilePath); // on windows, we still want to output forward slashes const unixFilePath = filePath.replace(/\\/g, '/'); const tests = fileResult.testResults.filter( (test) => predicate(fileResult, test) ); if (tests.length) { const lines = [unixFilePath].concat(tests.map((test) => '* ' + test.title)); formatted.push(lines.join('\n')); } }); formatted.sort(); return formatted.join('\n\n'); } function recordTests(maxWorkers, trackFacts) { runJest(maxWorkers) .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.numPassedTests + runResults.numFailedTests); // 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) .number('max-workers') .describe('max-workers', 'Number of workers to use for jest.') .default('max-workers', Math.max(os.cpus().length - 1, 1)) .boolean('track-facts') .describe('track-facts', 'Use facts-tracker to record passing tests.') .strict() .help() .argv; recordTests(argv.maxWorkers, argv.trackFacts); } module.exports = { wrapRunner, };