From bccd297f38c9f4cf6dbb16dffa7ee8753dbbd12f Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sun, 13 Jan 2019 05:34:42 -0500 Subject: [PATCH] Expose test file path within worker process This adds `test.meta.file` which exposes the filename of the test being run by AVA. Fixes #1976 --- docs/01-writing-tests.md | 10 ++++++++++ index.d.ts | 8 ++++++++ index.js.flow | 9 +++++++++ lib/create-chain.js | 4 +++- lib/runner.js | 5 ++++- test/api.js | 9 +++++++++ test/fixture/meta.js | 9 +++++++++ 7 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 test/fixture/meta.js diff --git a/docs/01-writing-tests.md b/docs/01-writing-tests.md index 7c9ae7258..ae42a3017 100644 --- a/docs/01-writing-tests.md +++ b/docs/01-writing-tests.md @@ -267,6 +267,16 @@ test('context is unicorn', t => { }); ``` +## Retrieving test meta data + +Helper files can determine the filename of the test being run by reading `test.meta.file`. This eliminates the need to pass `__filename` from the test to helpers. + +```js +import test from 'ava'; + +console.log('Test currently being run: ', test.meta.file); +``` + ## Reusing test logic through macros Additional arguments passed to the test declaration will be passed to the test implementation. This is useful for creating reusable test macros. diff --git a/index.d.ts b/index.d.ts index ce2f48760..0417d2354 100644 --- a/index.d.ts +++ b/index.d.ts @@ -468,6 +468,7 @@ export interface TestInterface { only: OnlyInterface; skip: SkipInterface; todo: TodoDeclaration; + meta: MetaInterface; } export interface AfterInterface { @@ -740,6 +741,11 @@ export interface TodoDeclaration { (title: string): void; } +export interface MetaInterface { + /** Path to the test file being executed. */ + file: string; +} + /** Call to declare a test, or chain to declare hooks or test modifiers */ declare const test: TestInterface; @@ -776,6 +782,8 @@ export const skip: SkipInterface; /** Declare a test that should be implemented later. */ export const todo: TodoDeclaration; +/** Meta data associated with the current process. */ +export const meta: MetaInterface; /* Tail type from . diff --git a/index.js.flow b/index.js.flow index 3c6c70f05..b9b9df983 100644 --- a/index.js.flow +++ b/index.js.flow @@ -707,6 +707,7 @@ export interface SerialInterface { only: OnlyInterface; skip: SkipInterface; todo: TodoDeclaration; + meta: MetaInterface; } export interface SkipInterface { @@ -725,6 +726,11 @@ export interface TodoDeclaration { (title: string): void; } +export interface MetaInterface { + /** Path to the test file being executed. */ + file: string; +} + /** Call to declare a test, or chain to declare hooks or test modifiers */ declare export default TestInterface<>; @@ -757,3 +763,6 @@ declare export var skip: SkipInterface<>; /** Declare a test that should be implemented later. */ declare export var todo: TodoDeclaration; + +/** Meta data associated with the current process. */ +declare export var meta: MetaInterface; diff --git a/lib/create-chain.js b/lib/create-chain.js index f512f8291..481a9e457 100644 --- a/lib/create-chain.js +++ b/lib/create-chain.js @@ -61,7 +61,7 @@ function createHookChain(hook, isAfterHook) { return hook; } -function createChain(fn, defaults) { +function createChain(fn, defaults, meta) { // Test chaining rules: // * `serial` must come at the start // * `only` and `skip` must come at the end @@ -108,6 +108,8 @@ function createChain(fn, defaults) { root.todo = startChain('test.todo', fn, Object.assign({}, defaults, {type: 'test', todo: true})); root.serial.todo = startChain('test.serial.todo', fn, Object.assign({}, defaults, {serial: true, type: 'test', todo: true})); + root.meta = meta; + return root; } diff --git a/lib/runner.js b/lib/runner.js index 0b3631f3e..8961fae13 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -40,6 +40,9 @@ class Runner extends Emittery { const uniqueTestTitles = new Set(); let hasStarted = false; let scheduledStart = false; + const meta = Object.freeze({ + file: options.file + }); this.chain = createChain((metadata, args) => { // eslint-disable-line complexity if (hasStarted) { throw new Error('All tests and hooks must be declared synchronously in your test file, and cannot be nested within other tests or hooks.'); @@ -159,7 +162,7 @@ class Runner extends Emittery { failing: false, callback: false, always: false - }); + }, meta); } compareTestSnapshot(options) { diff --git a/test/api.js b/test/api.js index 4e47cc63c..f828f1bb0 100644 --- a/test/api.js +++ b/test/api.js @@ -71,6 +71,15 @@ test('async/await support', t => { }); }); +test('test.meta.file', t => { + const api = apiCreator(); + + return api.run([path.join(__dirname, 'fixture/meta.js')]) + .then(runStatus => { + t.is(runStatus.stats.passedTests, 2); + }); +}); + test('fail-fast mode - single file & serial', t => { const api = apiCreator({ failFast: true diff --git a/test/fixture/meta.js b/test/fixture/meta.js new file mode 100644 index 000000000..c289c613f --- /dev/null +++ b/test/fixture/meta.js @@ -0,0 +1,9 @@ +import {default as test, meta} from '../..'; + +test('meta.file', t => { + t.is(meta.file, __filename); +}); + +test('test.meta.file', t => { + t.is(test.meta.file, __filename); +});