From 1222ce9538e4890c20af695e558e3ee490f5a41b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Sun, 26 Apr 2020 16:02:40 +0200 Subject: [PATCH] Run tests at selected line numbers Co-Authored-By: Mark Wubben --- docs/05-command-line.md | 64 ++++++++++- lib/api.js | 11 +- lib/cli.js | 15 ++- lib/fork.js | 4 +- lib/globs.js | 26 +++-- lib/line-numbers.js | 64 +++++++++++ lib/reporters/mini.js | 32 +++++- lib/reporters/verbose.js | 5 + lib/run-status.js | 10 +- lib/runner.js | 17 +++ lib/watcher.js | 5 +- lib/worker/line-numbers.js | 90 +++++++++++++++ lib/worker/subprocess.js | 15 +++ package-lock.json | 94 +++++++++++++-- package.json | 7 +- test-tap/fixture/line-numbers.js | 27 +++++ .../report/edgecases/ast-syntax-error.js | 7 ++ test-tap/fixture/report/edgecases/test.js | 3 + test-tap/helper/report.js | 31 +++-- test-tap/integration/line-numbers.js | 108 ++++++++++++++++++ test-tap/line-numbers.js | 83 ++++++++++++++ test-tap/reporters/mini.edgecases.v10.log | 9 ++ test-tap/reporters/mini.edgecases.v12.log | 9 ++ test-tap/reporters/mini.edgecases.v13.log | 9 ++ test-tap/reporters/mini.edgecases.v14.log | 9 ++ test-tap/reporters/mini.regular.v10.log | 4 +- test-tap/reporters/mini.regular.v12.log | 2 +- test-tap/reporters/mini.regular.v13.log | 2 +- test-tap/reporters/mini.regular.v14.log | 2 +- test-tap/reporters/tap.regular.v10.log | 16 ++- test-tap/reporters/tap.regular.v12.log | 7 +- test-tap/reporters/tap.regular.v13.log | 7 +- test-tap/reporters/tap.regular.v14.log | 7 +- test-tap/reporters/verbose.edgecases.v10.log | 6 + test-tap/reporters/verbose.edgecases.v12.log | 6 + test-tap/reporters/verbose.edgecases.v13.log | 6 + test-tap/reporters/verbose.edgecases.v14.log | 6 + test-tap/reporters/verbose.regular.v10.log | 4 +- test-tap/reporters/verbose.regular.v12.log | 2 +- test-tap/reporters/verbose.regular.v13.log | 2 +- test-tap/reporters/verbose.regular.v14.log | 2 +- 41 files changed, 762 insertions(+), 73 deletions(-) create mode 100644 lib/line-numbers.js create mode 100644 lib/worker/line-numbers.js create mode 100644 test-tap/fixture/line-numbers.js create mode 100644 test-tap/fixture/report/edgecases/ast-syntax-error.js create mode 100644 test-tap/fixture/report/edgecases/test.js create mode 100644 test-tap/integration/line-numbers.js create mode 100644 test-tap/line-numbers.js diff --git a/docs/05-command-line.md b/docs/05-command-line.md index c320fa37c..687f74358 100644 --- a/docs/05-command-line.md +++ b/docs/05-command-line.md @@ -15,7 +15,8 @@ Commands: Positionals: pattern Glob patterns to select what test files to run. Leave empty if you - want AVA to run all test files instead [string] + want AVA to run all test files instead. Add a colon and specify line + numbers of specific tests to run [string] Options: --version Show version number [boolean] @@ -42,6 +43,7 @@ Options: Examples: ava ava test.js + ava test.js:4,7-9 ``` *Note that the CLI will use your local install of AVA when available, even when run globally.* @@ -149,6 +151,66 @@ test(function foo(t) { }); ``` +## Running tests at specific line numbers + +AVA lets you run tests exclusively by referring to their line numbers. Target a single line, a range of lines or both. You can select any line number of a test. + +The format is a comma-separated list of `[X|Y-Z]` where `X`, `Y` and `Z` are integers between `1` and the last line number of the file. + +This feature is only available from the command line. It won't work if you use tools like `ts-node/register` or `@babel/register`, and it does not currently work with `@ava/babel` and `@ava/typescript`. + +### Running a single test + +To only run a particular test in a file, append the line number of the test to the path or pattern passed to AVA. + +Given the following test file: + +`test.js` + +```js +1: test('unicorn', t => { +2: t.pass(); +3: }); +4: +5: test('rainbow', t => { +6: t.fail(); +7: }); +``` + +Running `npx ava test.js:2` for would run the `unicorn` test. In fact you could use any line number between `1` and `3`. + +### Running multiple tests + +To run multiple tests, either target them one by one or select a range of line numbers. As line numbers are given per file, you can run multiple files with different line numbers for each file. If the same file is provided multiple times, line numbers are merged and only run once. + +### Examples + +Single line numbers: + +```console +npx ava test.js:2,9 +``` + +Range: + +```console +npx ava test.js:4-7 +``` + +Mix of single line number and range: + +```console +npx ava test.js:4,9-12 +``` + +Different files: + +```console +npx ava test.js:3 test2.js:4,7-9 +``` + +When running a file with and without line numbers, line numbers take precedence. + ## Resetting AVA's cache AVA may cache certain files, especially when you use our [`@ava/babel`](https://github.com/avajs/babel) provider. If it seems like your latest changes aren't being picked up by AVA you can reset the cache by running: diff --git a/lib/api.js b/lib/api.js index 4dad9cd21..92a9b9162 100644 --- a/lib/api.js +++ b/lib/api.js @@ -16,6 +16,7 @@ const isCi = require('./is-ci'); const RunStatus = require('./run-status'); const fork = require('./fork'); const serializeError = require('./serialize-error'); +const {getApplicableLineNumbers} = require('./line-numbers'); function resolveModules(modules) { return arrify(modules).map(name => { @@ -118,7 +119,11 @@ class Api extends Emittery { if (filter.length === 0) { selectedFiles = testFiles; } else { - selectedFiles = globs.applyTestFileFilter({cwd: this.options.projectDir, filter, testFiles}); + selectedFiles = globs.applyTestFileFilter({ + cwd: this.options.projectDir, + filter: filter.map(({pattern}) => pattern), + testFiles + }); } } } catch (error) { @@ -209,9 +214,11 @@ class Api extends Emittery { return; } + const lineNumbers = getApplicableLineNumbers(globs.normalizeFileForMatching(apiOptions.projectDir, file), filter); const options = { ...apiOptions, providerStates, + lineNumbers, recordNewSnapshots: !isCi, // If we're looking for matches, run every single test process in exclusive-only mode runOnlyExclusive: apiOptions.match.length > 0 || runtimeOptions.runOnlyExclusive === true @@ -223,7 +230,7 @@ class Api extends Emittery { } const worker = fork(file, options, apiOptions.nodeArguments); - runStatus.observeWorker(worker, file); + runStatus.observeWorker(worker, file, {selectingLines: lineNumbers.length > 0}); pendingWorkers.add(worker); worker.promise.then(() => { diff --git a/lib/cli.js b/lib/cli.js index b5af80d86..2a0fd4e49 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -120,7 +120,7 @@ exports.run = async () => { // eslint-disable-line complexity }) .command('* [...]', 'Run tests', yargs => yargs.options(FLAGS).positional('pattern', { array: true, - describe: 'Glob patterns to select what test files to run. Leave empty if you want AVA to run all test files instead', + describe: 'Glob patterns to select what test files to run. Leave empty if you want AVA to run all test files instead. Add a colon and specify line numbers of specific tests to run', type: 'string' })) .command( @@ -143,7 +143,7 @@ exports.run = async () => { // eslint-disable-line complexity } }).positional('pattern', { demand: true, - describe: 'Glob patterns to select a single test file to debug', + describe: 'Glob patterns to select a single test file to debug. Add a colon and specify line numbers of specific tests to run', type: 'string' }), argv => { @@ -163,6 +163,7 @@ exports.run = async () => { // eslint-disable-line complexity }) .example('$0') .example('$0 test.js') + .example('$0 test.js:4,7-9') .help(); const combined = {...conf}; @@ -263,9 +264,10 @@ exports.run = async () => { // eslint-disable-line complexity const TapReporter = require('./reporters/tap'); const Watcher = require('./watcher'); const normalizeExtensions = require('./extensions'); - const {normalizeGlobs, normalizePatterns} = require('./globs'); + const {normalizeGlobs, normalizePattern} = require('./globs'); const normalizeNodeArguments = require('./node-arguments'); const validateEnvironmentVariables = require('./environment-variables'); + const {splitPatternAndLineNumbers} = require('./line-numbers'); const providerManager = require('./provider-manager'); let pkg; @@ -349,7 +351,12 @@ exports.run = async () => { // eslint-disable-line complexity const match = combined.match === '' ? [] : arrify(combined.match); const input = debug ? debug.files : (argv.pattern || []); - const filter = normalizePatterns(input.map(fileOrPattern => path.relative(projectDir, path.resolve(process.cwd(), fileOrPattern)))); + const filter = input + .map(pattern => splitPatternAndLineNumbers(pattern)) + .map(({pattern, ...rest}) => ({ + pattern: normalizePattern(path.relative(projectDir, path.resolve(process.cwd(), pattern))), + ...rest + })); const api = new Api({ cacheEnabled: combined.cache !== false, diff --git a/lib/fork.js b/lib/fork.js index a1e6f0cd8..f393011e5 100644 --- a/lib/fork.js +++ b/lib/fork.js @@ -48,7 +48,9 @@ module.exports = (file, options, execArgv = process.execArgv) => { let forcedExit = false; const send = evt => { if (subprocess.connected && !finished && !forcedExit) { - subprocess.send({ava: evt}); + subprocess.send({ava: evt}, () => { + // Disregard errors. + }); } }; diff --git a/lib/globs.js b/lib/globs.js index 2d58e98de..4b51c59f5 100644 --- a/lib/globs.js +++ b/lib/globs.js @@ -23,23 +23,27 @@ const defaultIgnoredByWatcherPatterns = [ const buildExtensionPattern = extensions => extensions.length === 1 ? extensions[0] : `{${extensions.join(',')}}`; -function normalizePatterns(patterns) { +function normalizePattern(pattern) { // Always use `/` in patterns, harmonizing matching across platforms if (process.platform === 'win32') { - patterns = patterns.map(pattern => slash(pattern)); + pattern = slash(pattern); } - return patterns.map(pattern => { - if (pattern.startsWith('./')) { - return pattern.slice(2); - } + if (pattern.startsWith('./')) { + return pattern.slice(2); + } - if (pattern.startsWith('!./')) { - return `!${pattern.slice(3)}`; - } + if (pattern.startsWith('!./')) { + return `!${pattern.slice(3)}`; + } - return pattern; - }); + return pattern; +} + +exports.normalizePattern = normalizePattern; + +function normalizePatterns(patterns) { + return patterns.map(pattern => normalizePattern(pattern)); } exports.normalizePatterns = normalizePatterns; diff --git a/lib/line-numbers.js b/lib/line-numbers.js new file mode 100644 index 000000000..b44710419 --- /dev/null +++ b/lib/line-numbers.js @@ -0,0 +1,64 @@ +'use strict'; + +const micromatch = require('micromatch'); +const flatten = require('lodash/flatten'); + +const NUMBER_REGEX = /^\d+$/; +const RANGE_REGEX = /^(?\d+)-(?\d+)$/; +const LINE_NUMBERS_REGEX = /^(?:\d+(?:-\d+)?,?)+$/; +const DELIMITER = ':'; + +const distinctArray = array => [...new Set(array)]; +const sortNumbersAscending = array => { + const sorted = [...array]; + sorted.sort((a, b) => a - b); + return sorted; +}; + +const parseNumber = string => Number.parseInt(string, 10); +const removeAllWhitespace = string => string.replace(/\s/g, ''); +const range = (start, end) => new Array(end - start + 1).fill(start).map((element, index) => element + index); + +const parseLineNumbers = suffix => sortNumbersAscending(distinctArray(flatten( + suffix.split(',').map(part => { + if (NUMBER_REGEX.test(part)) { + return parseNumber(part); + } + + const {groups: {startGroup, endGroup}} = RANGE_REGEX.exec(part); + const start = parseNumber(startGroup); + const end = parseNumber(endGroup); + + if (start > end) { + return range(end, start); + } + + return range(start, end); + }) +))); + +function splitPatternAndLineNumbers(pattern) { + const parts = pattern.split(DELIMITER); + if (parts.length === 1) { + return {pattern, lineNumbers: null}; + } + + const suffix = removeAllWhitespace(parts.pop()); + if (!LINE_NUMBERS_REGEX.test(suffix)) { + return {pattern, lineNumbers: null}; + } + + return {pattern: parts.join(DELIMITER), lineNumbers: parseLineNumbers(suffix)}; +} + +exports.splitPatternAndLineNumbers = splitPatternAndLineNumbers; + +function getApplicableLineNumbers(normalizedFilePath, filter) { + return sortNumbersAscending(distinctArray(flatten( + filter + .filter(({pattern, lineNumbers}) => lineNumbers && micromatch.isMatch(normalizedFilePath, pattern)) + .map(({lineNumbers}) => lineNumbers) + ))); +} + +exports.getApplicableLineNumbers = getApplicableLineNumbers; diff --git a/lib/reporters/mini.js b/lib/reporters/mini.js index bd5a30ffb..4e221140e 100644 --- a/lib/reporters/mini.js +++ b/lib/reporters/mini.js @@ -109,8 +109,10 @@ class MiniReporter { this.failures = []; this.filesWithMissingAvaImports = new Set(); this.filesWithoutDeclaredTests = new Set(); + this.filesWithoutMatchedLineNumbers = new Set(); this.internalErrors = []; this.knownFailures = []; + this.lineNumberErrors = []; this.matching = false; this.prefixTitle = (testFile, title) => title; this.previousFailures = 0; @@ -148,6 +150,8 @@ class MiniReporter { } consumeStateChange(evt) { // eslint-disable-line complexity + const fileStats = this.stats && evt.testFile ? this.stats.byFile.get(evt.testFile) : null; + switch (evt.type) { case 'declared-test': // Ignore @@ -164,6 +168,10 @@ class MiniReporter { this.writeWithCounts(colors.error(`${figures.cross} Internal error`)); } + break; + case 'line-number-selection-error': + this.lineNumberErrors.push(evt); + this.writeWithCounts(colors.information(`${figures.warning} Could not parse ${this.relativeFile(evt.testFile)} for line number selection`)); break; case 'missing-ava-import': this.filesWithMissingAvaImports.add(evt.testFile); @@ -203,15 +211,18 @@ class MiniReporter { this.unhandledRejections.push(evt); break; case 'worker-failed': - if (this.stats.byFile.get(evt.testFile).declaredTests === 0) { + if (fileStats.declaredTests === 0) { this.filesWithoutDeclaredTests.add(evt.testFile); } break; case 'worker-finished': - if (this.stats.byFile.get(evt.testFile).declaredTests === 0) { + if (fileStats.declaredTests === 0) { this.filesWithoutDeclaredTests.add(evt.testFile); this.writeWithCounts(colors.error(`${figures.cross} No tests found in ${this.relativeFile(evt.testFile)}`)); + } else if (fileStats.selectingLines && fileStats.selectedTests === 0) { + this.filesWithoutMatchedLineNumbers.add(evt.testFile); + this.writeWithCounts(colors.error(`${figures.cross} Line numbers for ${this.relativeFile(evt.testFile)} did not match any tests`)); } break; @@ -432,7 +443,22 @@ class MiniReporter { } } - if (this.filesWithMissingAvaImports.size > 0 || this.filesWithoutDeclaredTests.size > 0) { + if (this.lineNumberErrors.length > 0) { + for (const evt of this.lineNumberErrors) { + this.lineWriter.writeLine(colors.information(`${figures.warning} Could not parse ${this.relativeFile(evt.testFile)} for line number selection`)); + } + } + + if (this.filesWithoutMatchedLineNumbers.size > 0) { + for (const testFile of this.filesWithoutMatchedLineNumbers) { + if (!this.filesWithMissingAvaImports.has(testFile) && !this.filesWithoutDeclaredTests.has(testFile)) { + this.lineWriter.writeLine(colors.error(`${figures.cross} Line numbers for ${this.relativeFile(testFile)} did not match any tests`) + firstLinePostfix); + firstLinePostfix = ''; + } + } + } + + if (this.filesWithMissingAvaImports.size > 0 || this.filesWithoutDeclaredTests.size > 0 || this.filesWithoutMatchedLineNumbers.size > 0) { this.lineWriter.writeLine(); } diff --git a/lib/reporters/verbose.js b/lib/reporters/verbose.js index f6ad4af3b..250dbfae6 100644 --- a/lib/reporters/verbose.js +++ b/lib/reporters/verbose.js @@ -132,6 +132,9 @@ class VerboseReporter { this.lineWriter.writeLine(); this.lineWriter.writeLine(); break; + case 'line-number-selection-error': + this.lineWriter.writeLine(colors.information(`${figures.warning} Could not parse ${this.relativeFile(evt.testFile)} for line number selection`)); + break; case 'missing-ava-import': this.filesWithMissingAvaImports.add(evt.testFile); this.lineWriter.writeLine(colors.error(`${figures.cross} No tests found in ${this.relativeFile(evt.testFile)}, make sure to import "ava" at the top of your test file`)); @@ -203,6 +206,8 @@ class VerboseReporter { if (!evt.forcedExit && !this.filesWithMissingAvaImports.has(evt.testFile)) { if (fileStats.declaredTests === 0) { this.lineWriter.writeLine(colors.error(`${figures.cross} No tests found in ${this.relativeFile(evt.testFile)}`)); + } else if (fileStats.selectingLines && fileStats.selectedTests === 0) { + this.lineWriter.writeLine(colors.error(`${figures.cross} Line numbers for ${this.relativeFile(evt.testFile)} did not match any tests`)); } else if (!this.failFastEnabled && fileStats.remainingTests > 0) { this.lineWriter.writeLine(colors.error(`${figures.cross} ${fileStats.remainingTests} ${plur('test', fileStats.remainingTests)} remaining in ${this.relativeFile(evt.testFile)}`)); } diff --git a/lib/run-status.js b/lib/run-status.js index 5b4e7bcf7..5726da58c 100644 --- a/lib/run-status.js +++ b/lib/run-status.js @@ -35,7 +35,7 @@ class RunStatus extends Emittery { }; } - observeWorker(worker, testFile) { + observeWorker(worker, testFile, stats) { this.stats.byFile.set(testFile, { declaredTests: 0, failedHooks: 0, @@ -45,10 +45,12 @@ class RunStatus extends Emittery { passedKnownFailingTests: 0, passedTests: 0, selectedTests: 0, + selectingLines: false, skippedTests: 0, todoTests: 0, uncaughtExceptions: 0, - unhandledRejections: 0 + unhandledRejections: 0, + ...stats }); this.pendingTests.set(testFile, new Set()); @@ -169,6 +171,10 @@ class RunStatus extends Emittery { return 1; } + if ([...this.stats.byFile.values()].some(stats => stats.selectingLines && stats.selectedTests === 0)) { + return 1; + } + return 0; } diff --git a/lib/runner.js b/lib/runner.js index c46fadf5d..0aec70a1f 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -16,6 +16,7 @@ class Runner extends Emittery { this.failFast = options.failFast === true; this.failWithoutAssertions = options.failWithoutAssertions !== false; this.file = options.file; + this.checkSelectedByLineNumbers = options.checkSelectedByLineNumbers; this.match = options.match || []; this.powerAssert = undefined; // Assigned later. this.projectDir = options.projectDir; @@ -75,6 +76,10 @@ class Runner extends Emittery { const {args, buildTitle, implementations, rawTitle} = parseTestArgs(testArgs); + if (this.checkSelectedByLineNumbers) { + metadata.selected = this.checkSelectedByLineNumbers(); + } + if (metadata.todo) { if (implementations.length > 0) { throw new TypeError('`todo` tests are not allowed to have an implementation. Use `test.skip()` for tests with an implementation.'); @@ -369,6 +374,10 @@ class Runner extends Emittery { continue; } + if (this.checkSelectedByLineNumbers && !task.metadata.selected) { + continue; + } + this.emit('stateChange', { type: 'selected-test', title: task.title, @@ -387,6 +396,10 @@ class Runner extends Emittery { continue; } + if (this.checkSelectedByLineNumbers && !task.metadata.selected) { + continue; + } + this.emit('stateChange', { type: 'selected-test', title: task.title, @@ -409,6 +422,10 @@ class Runner extends Emittery { continue; } + if (this.checkSelectedByLineNumbers && !task.metadata.selected) { + continue; + } + this.emit('stateChange', { type: 'selected-test', title: task.title, diff --git a/lib/watcher.js b/lib/watcher.js index 7dd71d4c5..6c6511f1d 100644 --- a/lib/watcher.js +++ b/lib/watcher.js @@ -85,6 +85,9 @@ class Watcher { this.runVector = 0; this.previousFiles = []; this.globs = {cwd: projectDir, ...globs}; + + const patternFilters = filter.map(({pattern}) => pattern); + this.providers = providers.filter(({level}) => level >= providerLevels.pathRewrites); this.run = (specificFiles = [], updateSnapshots = false) => { const clearLogOnNextRun = this.clearLogOnNextRun && this.runVector > 0; @@ -106,7 +109,7 @@ class Watcher { } if (filter.length > 0) { - specificFiles = applyTestFileFilter({cwd: projectDir, filter, testFiles: specificFiles}); + specificFiles = applyTestFileFilter({cwd: projectDir, filter: patternFilters, testFiles: specificFiles}); } this.pruneFailures(specificFiles); diff --git a/lib/worker/line-numbers.js b/lib/worker/line-numbers.js new file mode 100644 index 000000000..241511857 --- /dev/null +++ b/lib/worker/line-numbers.js @@ -0,0 +1,90 @@ +function parse(file) { + const fs = require('fs'); + const acorn = require('acorn'); + const walk = require('acorn-walk'); + + const ast = acorn.parse(fs.readFileSync(file, 'utf8'), { + ecmaVersion: 11, + locations: true + }); + + const locations = []; + walk.simple(ast, { + CallExpression(node) { + locations.push(node.loc); + } + }); + + // Walking is depth-first, but we want to sort these breadth-first. + locations.sort((a, b) => { + if (a.start.line === b.start.line) { + return a.start.column - b.start.column; + } + + return a.start.line - b.start.line; + }); + + return locations; +} + +function findTest(locations, declaration) { + // Find all calls that span the test declaration. + const spans = locations.filter(loc => { + if (loc.start.line > declaration.line || loc.end.line < declaration.line) { + return false; + } + + if (loc.start.line === declaration.line && loc.start.column > declaration.column) { + return false; + } + + if (loc.end.line === declaration.line && loc.end.column < declaration.column) { + return false; + } + + return true; + }); + + // Locations should be sorted by source order, so the last span must be the test. + return spans.pop(); +} + +const range = (start, end) => new Array(end - start + 1).fill(start).map((element, index) => element + index); + +module.exports = ({file, lineNumbers = []}) => { + if (lineNumbers.length === 0) { + return undefined; + } + + // Avoid loading these until we actually need to select tests by line number. + const callsites = require('callsites'); + const sourceMapSupport = require('source-map-support'); + + const locations = parse(file); + const selected = new Set(lineNumbers); + + return () => { + // Assume this is called from a test declaration, which is located in the file. + // If not… don't select the test! + const callSite = callsites().find(callSite => callSite.getFileName() === file); + if (!callSite) { + return false; + } + + // FIXME: This assumes the callSite hasn't already been adjusted. It's likely + // that if `source-map-support/register` has been loaded, this would result + // in the wrong location. + const sourceCallSite = sourceMapSupport.wrapCallSite(callSite); + const start = { + line: sourceCallSite.getLineNumber(), + column: sourceCallSite.getColumnNumber() - 1 // Use 0-indexed columns. + }; + + const test = findTest(locations, start); + if (!test) { + return false; + } + + return range(test.start.line, test.end.line).some(line => selected.has(line)); + }; +}; diff --git a/lib/worker/subprocess.js b/lib/worker/subprocess.js index d22081af4..2b3ae3bf6 100644 --- a/lib/worker/subprocess.js +++ b/lib/worker/subprocess.js @@ -30,6 +30,7 @@ ipc.options.then(async options => { const Runner = require('../runner'); const serializeError = require('../serialize-error'); const dependencyTracking = require('./dependency-tracker'); + const lineNumberSelection = require('./line-numbers'); async function exit(code) { if (!process.exitCode) { @@ -41,7 +42,21 @@ ipc.options.then(async options => { process.exit(); // eslint-disable-line unicorn/no-process-exit } + // TODO: Initialize providers here, then pass to lineNumberSelection() so they + // can be used to parse the test file. + let checkSelectedByLineNumbers; + try { + checkSelectedByLineNumbers = lineNumberSelection({ + file: options.file, + lineNumbers: options.lineNumbers + }); + } catch (error) { + ipc.send({type: 'line-number-selection-error', err: serializeError('Line number selection error', false, error, options.file)}); + checkSelectedByLineNumbers = () => false; + } + const runner = new Runner({ + checkSelectedByLineNumbers, experiments: options.experiments, failFast: options.failFast, failWithoutAssertions: options.failWithoutAssertions, diff --git a/package-lock.json b/package-lock.json index c36b1ce18..076bab473 100644 --- a/package-lock.json +++ b/package-lock.json @@ -248,6 +248,13 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } } }, "color-convert": { @@ -284,6 +291,16 @@ "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", "dev": true }, + "@babel/plugin-proposal-do-expressions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-do-expressions/-/plugin-proposal-do-expressions-7.8.3.tgz", + "integrity": "sha512-NoMcN+0+SS1DVswjDCfz+Jfm9ViOYuFtv1lm0QInEugbEXK2iH3jeSq38WmIiTP+2QKqo2zt8xku77gqHINZkw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-do-expressions": "^7.8.3" + } + }, "@babel/plugin-proposal-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", @@ -314,6 +331,15 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.0" } }, + "@babel/plugin-syntax-do-expressions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-do-expressions/-/plugin-syntax-do-expressions-7.8.3.tgz", + "integrity": "sha512-puRiUTVDQ69iRX41eeVWqOftZK31waWqZfwKB/TGzPfgi7097twx/DpwfOfyqEGqYtvpQF3jpHwT6UBzvSyAjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", @@ -646,8 +672,7 @@ "acorn": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", - "dev": true + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, "acorn-jsx": { "version": "5.2.0", @@ -655,6 +680,11 @@ "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", "dev": true }, + "acorn-walk": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==" + }, "aggregate-error": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", @@ -1353,8 +1383,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camelcase": { "version": "5.3.1", @@ -1483,6 +1512,14 @@ "dev": true, "requires": { "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "clean-stack": { @@ -2321,11 +2358,6 @@ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, "eslint": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", @@ -2433,6 +2465,12 @@ } } }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, "eslint-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", @@ -2622,6 +2660,14 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "color-convert": { @@ -2893,6 +2939,14 @@ "requires": { "escape-string-regexp": "^1.0.5", "ignore": "^5.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "eslint-plugin-import": { @@ -3549,6 +3603,13 @@ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "requires": { "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } } }, "file-entry-cache": { @@ -5028,6 +5089,13 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } } }, "color-convert": { @@ -9624,6 +9692,14 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "ci-info": { diff --git a/package.json b/package.json index 18f7da492..3721aaaeb 100644 --- a/package.json +++ b/package.json @@ -56,9 +56,12 @@ ], "dependencies": { "@concordance/react": "^2.0.0", + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", "ansi-styles": "^4.2.1", "arrgv": "^1.0.2", "arrify": "^2.0.1", + "callsites": "^3.1.0", "chalk": "^4.0.0", "chokidar": "^3.3.1", "chunkd": "^2.0.1", @@ -110,6 +113,7 @@ }, "devDependencies": { "@ava/babel": "^1.0.1", + "@babel/plugin-proposal-do-expressions": "^7.8.3", "@sinonjs/fake-timers": "^6.0.1", "ansi-escapes": "^4.3.1", "delay": "^4.3.0", @@ -139,7 +143,8 @@ "test-tap/fixture/ava-paths/target/test.js", "test-tap/fixture/{source-map-initial,syntax-error}.js", "test-tap/fixture/snapshots/test-sourcemaps/build/**", - "test-tap/fixture/power-assert.js" + "test-tap/fixture/power-assert.js", + "test-tap/fixture/report/edgecases/ast-syntax-error.js" ], "rules": { "no-use-extend-native/no-use-extend-native": "off", diff --git a/test-tap/fixture/line-numbers.js b/test-tap/fixture/line-numbers.js new file mode 100644 index 000000000..a1a2a58d1 --- /dev/null +++ b/test-tap/fixture/line-numbers.js @@ -0,0 +1,27 @@ +const test = require('../..'); + +test('unicorn', t => { + t.pass(); +}); + +test('rainbow', t => { + t.pass(); +}); + +test.serial('cat', t => { + t.pass(); +}); + +test.todo('dog'); + +/* eslint-disable max-statements-per-line */ +test('sun', t => t.pass()); test('moon', t => { + t.pass(); +}); +/* eslint-enable max-statements-per-line */ + +(() => { + test('nested call', t => { + t.pass(); + }); +})(); diff --git a/test-tap/fixture/report/edgecases/ast-syntax-error.js b/test-tap/fixture/report/edgecases/ast-syntax-error.js new file mode 100644 index 000000000..34aee0ec7 --- /dev/null +++ b/test-tap/fixture/report/edgecases/ast-syntax-error.js @@ -0,0 +1,7 @@ +const test = require('../../../..'); + +const fn = do { + t => t.pass(); +}; + +test('fn', fn); diff --git a/test-tap/fixture/report/edgecases/test.js b/test-tap/fixture/report/edgecases/test.js new file mode 100644 index 000000000..16e3fae53 --- /dev/null +++ b/test-tap/fixture/report/edgecases/test.js @@ -0,0 +1,3 @@ +const test = require('../../../..'); + +test('passes', t => t.pass()); diff --git a/test-tap/helper/report.js b/test-tap/helper/report.js index aa22c7654..4479193b3 100644 --- a/test-tap/helper/report.js +++ b/test-tap/helper/report.js @@ -67,12 +67,19 @@ exports.sanitizers = { exports.projectDir = type => path.join(__dirname, '../fixture/report', type.toLowerCase()); -const run = (type, reporter, match = []) => { +const run = (type, reporter, {match = [], filter} = {}) => { const projectDir = exports.projectDir(type); const providers = [{ type: 'babel', - main: providerManager.babel(projectDir).main({config: true}) + level: 'ava-3', + main: providerManager.babel(projectDir).main({ + config: { + testOptions: { + plugins: ['@babel/plugin-proposal-do-expressions'] + } + } + }) }]; const options = { @@ -93,7 +100,7 @@ const run = (type, reporter, match = []) => { chalkOptions: {level: 1} }; - options.globs = normalizeGlobs({extensions: options.extensions, providers: []}); + options.globs = normalizeGlobs({extensions: options.extensions, files: ['*'], providers: []}); const api = createApi(options); api.on('run', plan => reporter.startRun(plan)); @@ -115,18 +122,18 @@ const run = (type, reporter, match = []) => { unique: true }).sort(); if (type !== 'watch') { - return api.run({files}).then(() => { + return api.run({files, filter}).then(() => { reporter.endRun(); }); } // Mimick watch mode - return api.run({files, runtimeOptions: {clearLogOnNextRun: false, previousFailures: 0, runVector: 1}}).then(() => { + return api.run({files, filter, runtimeOptions: {clearLogOnNextRun: false, previousFailures: 0, runVector: 1}}).then(() => { reporter.endRun(); - return api.run({files, runtimeOptions: {clearLogOnNextRun: true, previousFailures: 2, runVector: 2}}); + return api.run({files, filter, runtimeOptions: {clearLogOnNextRun: true, previousFailures: 2, runVector: 2}}); }).then(() => { reporter.endRun(); - return api.run({files, runtimeOptions: {clearLogOnNextRun: false, previousFailures: 0, runVector: 3}}); + return api.run({files, filter, runtimeOptions: {clearLogOnNextRun: false, previousFailures: 0, runVector: 3}}); }).then(() => { reporter.endRun(); }); @@ -138,6 +145,12 @@ exports.failFast2 = reporter => run('failFast2', reporter); exports.only = reporter => run('only', reporter); exports.timeoutInSingleFile = reporter => run('timeoutInSingleFile', reporter); exports.timeoutInMultipleFiles = reporter => run('timeoutInMultipleFiles', reporter); -exports.timeoutWithMatch = reporter => run('timeoutWithMatch', reporter, ['*needle*']); +exports.timeoutWithMatch = reporter => run('timeoutWithMatch', reporter, {match: ['*needle*']}); exports.watch = reporter => run('watch', reporter); -exports.edgeCases = reporter => run('edgeCases', reporter); +exports.edgeCases = reporter => run('edgeCases', reporter, { + filter: [ + {pattern: '**/*'}, + {pattern: '**/test.js', lineNumbers: [2]}, + {pattern: '**/ast-syntax-error.js', lineNumbers: [7]} + ] +}); diff --git a/test-tap/integration/line-numbers.js b/test-tap/integration/line-numbers.js new file mode 100644 index 000000000..899dbbf2a --- /dev/null +++ b/test-tap/integration/line-numbers.js @@ -0,0 +1,108 @@ +'use strict'; +const {test} = require('tap'); +const {execCli} = require('../helper/cli'); + +test('select test by line number', t => { + execCli([ + 'line-numbers.js', + 'line-numbers.js:3' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /unicorn/); + t.match(stdout, /1 test passed/); + t.notMatch(stdout, /todo/); + t.end(); + }); +}); + +test('select serial test by line number', t => { + execCli([ + 'line-numbers.js:11' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /cat/); + t.match(stdout, /1 test passed/); + t.notMatch(stdout, /todo/); + t.end(); + }); +}); + +test('select todo test by line number', t => { + execCli([ + 'line-numbers.js:15' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /dog/); + t.match(stdout, /1 test todo/); + t.end(); + }); +}); + +test('select tests by line number range', t => { + execCli([ + 'line-numbers.js:5-7' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /unicorn/); + t.match(stdout, /rainbow/); + t.match(stdout, /2 tests passed/); + t.notMatch(stdout, /todo/); + t.end(); + }); +}); + +test('select two tests declared on same line', t => { + execCli([ + 'line-numbers.js:18' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /sun/); + t.match(stdout, /moon/); + t.match(stdout, /2 tests passed/); + t.notMatch(stdout, /todo/); + t.end(); + }); +}); + +test('select only one of two tests declared on same line', t => { + execCli([ + 'line-numbers.js:19' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /moon/); + t.match(stdout, /1 test passed/); + t.notMatch(stdout, /todo/); + t.end(); + }); +}); + +test('no test selected by line number', t => { + execCli([ + 'line-numbers.js:6' + ], (error, stdout) => { + t.ok(error); + t.match(stdout, /Line numbers for line-numbers\.js did not match any tests/); + t.end(); + }); +}); + +test('parent call is not selected', t => { + execCli([ + 'line-numbers.js:23' + ], (error, stdout) => { + t.ok(error); + t.match(stdout, /Line numbers for line-numbers\.js did not match any tests/); + t.end(); + }); +}); + +test('nested call is selected', t => { + execCli([ + 'line-numbers.js:24' + ], (error, stdout) => { + t.ifError(error); + t.match(stdout, /nested/); + t.match(stdout, /1 test passed/); + t.end(); + }); +}); diff --git a/test-tap/line-numbers.js b/test-tap/line-numbers.js new file mode 100644 index 000000000..fecb9c93e --- /dev/null +++ b/test-tap/line-numbers.js @@ -0,0 +1,83 @@ +'use strict'; + +const {test} = require('tap'); +const { + splitPatternAndLineNumbers, + getApplicableLineNumbers +} = require('../lib/line-numbers'); + +test('no line numbers', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js'), {pattern: 'test.js', lineNumbers: null}); + t.end(); +}); + +test('delimeter but no line numbers suffix', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:foo'), {pattern: 'test.js:foo', lineNumbers: null}); + t.strictDeepEqual(splitPatternAndLineNumbers('test:3.js'), {pattern: 'test:3.js', lineNumbers: null}); + t.end(); +}); + +test('single line number', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:2'), {pattern: 'test.js', lineNumbers: [2]}); + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:10'), {pattern: 'test.js', lineNumbers: [10]}); + t.end(); +}); + +test('multiple line numbers', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:2,10'), {pattern: 'test.js', lineNumbers: [2, 10]}); + t.end(); +}); + +test('single range', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:2-4'), {pattern: 'test.js', lineNumbers: [2, 3, 4]}); + t.end(); +}); + +test('multiple ranges', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:2-4,8-10'), {pattern: 'test.js', lineNumbers: [2, 3, 4, 8, 9, 10]}); + t.end(); +}); + +test('overlapping ranges', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:2-4,3-5'), {pattern: 'test.js', lineNumbers: [2, 3, 4, 5]}); + t.end(); +}); + +test('mix of number and range', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:2,8-10'), {pattern: 'test.js', lineNumbers: [2, 8, 9, 10]}); + t.end(); +}); + +test('overlapping number and range', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js:3,2-4'), {pattern: 'test.js', lineNumbers: [2, 3, 4]}); + t.end(); +}); + +test('handle whitespace', t => { + t.strictDeepEqual(splitPatternAndLineNumbers('test.js: 2 , 3 - 4 '), {pattern: 'test.js', lineNumbers: [2, 3, 4]}); + t.end(); +}); + +test('ignore non-matching patterns', t => { + t.strictDeepEqual( + getApplicableLineNumbers('test.js', [{pattern: 'test.js', lineNumbers: [2]}, {pattern: 'foo.js', lineNumbers: [3]}]), + [2] + ); + t.end(); +}); + +test('deduplicate line numbers', t => { + t.strictDeepEqual( + getApplicableLineNumbers('test.js', [{pattern: 'test.js', lineNumbers: [2, 3, 4]}, {pattern: 'test.js', lineNumbers: [3, 4, 5]}]), + [2, 3, 4, 5] + ); + t.end(); +}); + +test('sort line numbers', t => { + t.strictDeepEqual( + getApplicableLineNumbers('test.js', [{pattern: 'test.js', lineNumbers: [1, 3, 5]}, {pattern: 'test.js', lineNumbers: [2, 4, 6]}]), + [1, 2, 3, 4, 5, 6] + ); + t.end(); +}); diff --git a/test-tap/reporters/mini.edgecases.v10.log b/test-tap/reporters/mini.edgecases.v10.log index 0a481d9dd..50d9abe7e 100644 --- a/test-tap/reporters/mini.edgecases.v10.log +++ b/test-tap/reporters/mini.edgecases.v10.log @@ -3,15 +3,24 @@ ---tty-stream-chunk-separator * ---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ⚠ Could not parse ast-syntax-error.js for line number selection---tty-stream-chunk-separator +---tty-stream-chunk-separator +* ✖ Line numbers for ast-syntax-error.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator * ✖ No tests found in ava-import-no-test-declaration.js---tty-stream-chunk-separator ---tty-stream-chunk-separator * ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ✖ Line numbers for test.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator [?25h ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ✖ No tests found in ava-import-no-test-declaration.js ✖ No tests found in import-and-use-test-member.js ✖ No tests found in throws.js + ⚠ Could not parse ast-syntax-error.js for line number selection + ✖ Line numbers for ast-syntax-error.js did not match any tests + ✖ Line numbers for test.js did not match any tests 2 uncaught exceptions diff --git a/test-tap/reporters/mini.edgecases.v12.log b/test-tap/reporters/mini.edgecases.v12.log index 0a481d9dd..50d9abe7e 100644 --- a/test-tap/reporters/mini.edgecases.v12.log +++ b/test-tap/reporters/mini.edgecases.v12.log @@ -3,15 +3,24 @@ ---tty-stream-chunk-separator * ---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ⚠ Could not parse ast-syntax-error.js for line number selection---tty-stream-chunk-separator +---tty-stream-chunk-separator +* ✖ Line numbers for ast-syntax-error.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator * ✖ No tests found in ava-import-no-test-declaration.js---tty-stream-chunk-separator ---tty-stream-chunk-separator * ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ✖ Line numbers for test.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator [?25h ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ✖ No tests found in ava-import-no-test-declaration.js ✖ No tests found in import-and-use-test-member.js ✖ No tests found in throws.js + ⚠ Could not parse ast-syntax-error.js for line number selection + ✖ Line numbers for ast-syntax-error.js did not match any tests + ✖ Line numbers for test.js did not match any tests 2 uncaught exceptions diff --git a/test-tap/reporters/mini.edgecases.v13.log b/test-tap/reporters/mini.edgecases.v13.log index 0a481d9dd..50d9abe7e 100644 --- a/test-tap/reporters/mini.edgecases.v13.log +++ b/test-tap/reporters/mini.edgecases.v13.log @@ -3,15 +3,24 @@ ---tty-stream-chunk-separator * ---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ⚠ Could not parse ast-syntax-error.js for line number selection---tty-stream-chunk-separator +---tty-stream-chunk-separator +* ✖ Line numbers for ast-syntax-error.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator * ✖ No tests found in ava-import-no-test-declaration.js---tty-stream-chunk-separator ---tty-stream-chunk-separator * ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ✖ Line numbers for test.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator [?25h ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ✖ No tests found in ava-import-no-test-declaration.js ✖ No tests found in import-and-use-test-member.js ✖ No tests found in throws.js + ⚠ Could not parse ast-syntax-error.js for line number selection + ✖ Line numbers for ast-syntax-error.js did not match any tests + ✖ Line numbers for test.js did not match any tests 2 uncaught exceptions diff --git a/test-tap/reporters/mini.edgecases.v14.log b/test-tap/reporters/mini.edgecases.v14.log index 0a481d9dd..50d9abe7e 100644 --- a/test-tap/reporters/mini.edgecases.v14.log +++ b/test-tap/reporters/mini.edgecases.v14.log @@ -3,15 +3,24 @@ ---tty-stream-chunk-separator * ---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ⚠ Could not parse ast-syntax-error.js for line number selection---tty-stream-chunk-separator +---tty-stream-chunk-separator +* ✖ Line numbers for ast-syntax-error.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator * ✖ No tests found in ava-import-no-test-declaration.js---tty-stream-chunk-separator ---tty-stream-chunk-separator * ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file---tty-stream-chunk-separator ---tty-stream-chunk-separator +* ✖ Line numbers for test.js did not match any tests---tty-stream-chunk-separator +---tty-stream-chunk-separator [?25h ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ✖ No tests found in ava-import-no-test-declaration.js ✖ No tests found in import-and-use-test-member.js ✖ No tests found in throws.js + ⚠ Could not parse ast-syntax-error.js for line number selection + ✖ Line numbers for ast-syntax-error.js did not match any tests + ✖ Line numbers for test.js did not match any tests 2 uncaught exceptions diff --git a/test-tap/reporters/mini.regular.v10.log b/test-tap/reporters/mini.regular.v10.log index 73e6eabbe..cc972b54a 100644 --- a/test-tap/reporters/mini.regular.v10.log +++ b/test-tap/reporters/mini.regular.v10.log @@ -350,7 +350,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › t.throws._avaThrowsHelperEnd (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) › t (test-tap/fixture/report/regular/traces-in-t-throws.js:12:4) › process._tickCallback (internal/process/next_tick.js:68:7) @@ -371,7 +371,7 @@ } › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.notThrows (test-tap/fixture/report/regular/traces-in-t-throws.js:16:20) + › t.notThrows._avaThrowsHelperEnd (test-tap/fixture/report/regular/traces-in-t-throws.js:16:20) › t (test-tap/fixture/report/regular/traces-in-t-throws.js:16:4) › process._tickCallback (internal/process/next_tick.js:68:7) diff --git a/test-tap/reporters/mini.regular.v12.log b/test-tap/reporters/mini.regular.v12.log index a52d375a9..a51c5b533 100644 --- a/test-tap/reporters/mini.regular.v12.log +++ b/test-tap/reporters/mini.regular.v12.log @@ -339,7 +339,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws.instanceOf (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 › test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 diff --git a/test-tap/reporters/mini.regular.v13.log b/test-tap/reporters/mini.regular.v13.log index a52d375a9..a51c5b533 100644 --- a/test-tap/reporters/mini.regular.v13.log +++ b/test-tap/reporters/mini.regular.v13.log @@ -339,7 +339,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws.instanceOf (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 › test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 diff --git a/test-tap/reporters/mini.regular.v14.log b/test-tap/reporters/mini.regular.v14.log index a52d375a9..a51c5b533 100644 --- a/test-tap/reporters/mini.regular.v14.log +++ b/test-tap/reporters/mini.regular.v14.log @@ -339,7 +339,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws.instanceOf (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 › test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 diff --git a/test-tap/reporters/tap.regular.v10.log b/test-tap/reporters/tap.regular.v10.log index 94639dd60..429c8cad8 100644 --- a/test-tap/reporters/tap.regular.v10.log +++ b/test-tap/reporters/tap.regular.v10.log @@ -183,10 +183,14 @@ not ok 17 - traces-in-t-throws › throws message: 'uh-oh', } 'Expected instance of:': 'Function TypeError {}' - at: |- + at: >- throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - t.throws (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + + t.throws._avaThrowsHelperEnd + (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + t (test-tap/fixture/report/regular/traces-in-t-throws.js:12:4) + process._tickCallback (internal/process/next_tick.js:68:7) ... ---tty-stream-chunk-separator @@ -200,10 +204,14 @@ not ok 18 - traces-in-t-throws › notThrows Error { message: 'uh-oh', } - at: |- + at: >- throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - t.notThrows (test-tap/fixture/report/regular/traces-in-t-throws.js:16:20) + + t.notThrows._avaThrowsHelperEnd + (test-tap/fixture/report/regular/traces-in-t-throws.js:16:20) + t (test-tap/fixture/report/regular/traces-in-t-throws.js:16:4) + process._tickCallback (internal/process/next_tick.js:68:7) ... ---tty-stream-chunk-separator diff --git a/test-tap/reporters/tap.regular.v12.log b/test-tap/reporters/tap.regular.v12.log index 5a4961709..c96e4232d 100644 --- a/test-tap/reporters/tap.regular.v12.log +++ b/test-tap/reporters/tap.regular.v12.log @@ -171,12 +171,9 @@ not ok 17 - traces-in-t-throws › throws message: 'uh-oh', } 'Expected instance of:': 'Function TypeError {}' - at: >- + at: |- throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - - t.throws.instanceOf - (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) - + test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 ... ---tty-stream-chunk-separator diff --git a/test-tap/reporters/tap.regular.v13.log b/test-tap/reporters/tap.regular.v13.log index 5a4961709..c96e4232d 100644 --- a/test-tap/reporters/tap.regular.v13.log +++ b/test-tap/reporters/tap.regular.v13.log @@ -171,12 +171,9 @@ not ok 17 - traces-in-t-throws › throws message: 'uh-oh', } 'Expected instance of:': 'Function TypeError {}' - at: >- + at: |- throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - - t.throws.instanceOf - (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) - + test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 ... ---tty-stream-chunk-separator diff --git a/test-tap/reporters/tap.regular.v14.log b/test-tap/reporters/tap.regular.v14.log index 5a4961709..c96e4232d 100644 --- a/test-tap/reporters/tap.regular.v14.log +++ b/test-tap/reporters/tap.regular.v14.log @@ -171,12 +171,9 @@ not ok 17 - traces-in-t-throws › throws message: 'uh-oh', } 'Expected instance of:': 'Function TypeError {}' - at: >- + at: |- throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - - t.throws.instanceOf - (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) - + test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 ... ---tty-stream-chunk-separator diff --git a/test-tap/reporters/verbose.edgecases.v10.log b/test-tap/reporters/verbose.edgecases.v10.log index c46f3ad2e..002c0f1b0 100644 --- a/test-tap/reporters/verbose.edgecases.v10.log +++ b/test-tap/reporters/verbose.edgecases.v10.log @@ -1,4 +1,8 @@ +---tty-stream-chunk-separator + ⚠ Could not parse ast-syntax-error.js for line number selection +---tty-stream-chunk-separator + ✖ Line numbers for ast-syntax-error.js did not match any tests ---tty-stream-chunk-separator ✖ No tests found in ava-import-no-test-declaration.js ---tty-stream-chunk-separator @@ -20,6 +24,8 @@ ---tty-stream-chunk-separator ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ---tty-stream-chunk-separator + ✖ Line numbers for test.js did not match any tests +---tty-stream-chunk-separator Uncaught exception in throws.js diff --git a/test-tap/reporters/verbose.edgecases.v12.log b/test-tap/reporters/verbose.edgecases.v12.log index c46f3ad2e..002c0f1b0 100644 --- a/test-tap/reporters/verbose.edgecases.v12.log +++ b/test-tap/reporters/verbose.edgecases.v12.log @@ -1,4 +1,8 @@ +---tty-stream-chunk-separator + ⚠ Could not parse ast-syntax-error.js for line number selection +---tty-stream-chunk-separator + ✖ Line numbers for ast-syntax-error.js did not match any tests ---tty-stream-chunk-separator ✖ No tests found in ava-import-no-test-declaration.js ---tty-stream-chunk-separator @@ -20,6 +24,8 @@ ---tty-stream-chunk-separator ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ---tty-stream-chunk-separator + ✖ Line numbers for test.js did not match any tests +---tty-stream-chunk-separator Uncaught exception in throws.js diff --git a/test-tap/reporters/verbose.edgecases.v13.log b/test-tap/reporters/verbose.edgecases.v13.log index c46f3ad2e..002c0f1b0 100644 --- a/test-tap/reporters/verbose.edgecases.v13.log +++ b/test-tap/reporters/verbose.edgecases.v13.log @@ -1,4 +1,8 @@ +---tty-stream-chunk-separator + ⚠ Could not parse ast-syntax-error.js for line number selection +---tty-stream-chunk-separator + ✖ Line numbers for ast-syntax-error.js did not match any tests ---tty-stream-chunk-separator ✖ No tests found in ava-import-no-test-declaration.js ---tty-stream-chunk-separator @@ -20,6 +24,8 @@ ---tty-stream-chunk-separator ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ---tty-stream-chunk-separator + ✖ Line numbers for test.js did not match any tests +---tty-stream-chunk-separator Uncaught exception in throws.js diff --git a/test-tap/reporters/verbose.edgecases.v14.log b/test-tap/reporters/verbose.edgecases.v14.log index c46f3ad2e..002c0f1b0 100644 --- a/test-tap/reporters/verbose.edgecases.v14.log +++ b/test-tap/reporters/verbose.edgecases.v14.log @@ -1,4 +1,8 @@ +---tty-stream-chunk-separator + ⚠ Could not parse ast-syntax-error.js for line number selection +---tty-stream-chunk-separator + ✖ Line numbers for ast-syntax-error.js did not match any tests ---tty-stream-chunk-separator ✖ No tests found in ava-import-no-test-declaration.js ---tty-stream-chunk-separator @@ -20,6 +24,8 @@ ---tty-stream-chunk-separator ✖ No tests found in no-ava-import.js, make sure to import "ava" at the top of your test file ---tty-stream-chunk-separator + ✖ Line numbers for test.js did not match any tests +---tty-stream-chunk-separator Uncaught exception in throws.js diff --git a/test-tap/reporters/verbose.regular.v10.log b/test-tap/reporters/verbose.regular.v10.log index f72e5399a..efc5e3a59 100644 --- a/test-tap/reporters/verbose.regular.v10.log +++ b/test-tap/reporters/verbose.regular.v10.log @@ -312,7 +312,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › t.throws._avaThrowsHelperEnd (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) › t (test-tap/fixture/report/regular/traces-in-t-throws.js:12:4) › process._tickCallback (internal/process/next_tick.js:68:7) @@ -333,7 +333,7 @@ } › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.notThrows (test-tap/fixture/report/regular/traces-in-t-throws.js:16:20) + › t.notThrows._avaThrowsHelperEnd (test-tap/fixture/report/regular/traces-in-t-throws.js:16:20) › t (test-tap/fixture/report/regular/traces-in-t-throws.js:16:4) › process._tickCallback (internal/process/next_tick.js:68:7) diff --git a/test-tap/reporters/verbose.regular.v12.log b/test-tap/reporters/verbose.regular.v12.log index 418166d85..320db8ee1 100644 --- a/test-tap/reporters/verbose.regular.v12.log +++ b/test-tap/reporters/verbose.regular.v12.log @@ -302,7 +302,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws.instanceOf (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 › test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 diff --git a/test-tap/reporters/verbose.regular.v13.log b/test-tap/reporters/verbose.regular.v13.log index 418166d85..320db8ee1 100644 --- a/test-tap/reporters/verbose.regular.v13.log +++ b/test-tap/reporters/verbose.regular.v13.log @@ -302,7 +302,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws.instanceOf (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 › test-tap/fixture/report/regular/traces-in-t-throws.js:12:4 diff --git a/test-tap/reporters/verbose.regular.v14.log b/test-tap/reporters/verbose.regular.v14.log index 418166d85..320db8ee1 100644 --- a/test-tap/reporters/verbose.regular.v14.log +++ b/test-tap/reporters/verbose.regular.v14.log @@ -302,7 +302,7 @@ Function TypeError {} › throwError (test-tap/fixture/report/regular/traces-in-t-throws.js:4:8) - › t.throws.instanceOf (test-tap/fixture/report/regular/traces-in-t-throws.js:12:17) + › test-tap/fixture/report/regular/traces-in-t-throws.js:12:17 › test-tap/fixture/report/regular/traces-in-t-throws.js:12:4