77import avaTest , {
88 ExecutionContext ,
99 Implementation ,
10- OneOrMoreMacros ,
10+ ImplementationFn ,
11+ Macro ,
12+ MacroDeclarationOptions ,
13+ MacroFn ,
14+ TestFn ,
1115} from 'ava' ;
1216import * as assert from 'assert' ;
1317import throat from 'throat' ;
@@ -58,59 +62,72 @@ export const test = createTestInterface({
5862// In case someone wants to `const test = context()`
5963export const context = test . context ;
6064
65+ export type SimpleTitleFn = ( providedTitle : string | undefined ) => string ;
66+ export type SimpleImplementationFn < Context = unknown > = (
67+ t : ExecutionContext < Context >
68+ ) => PromiseLike < void > ;
69+ export type SimpleContextFn < Context , T > = (
70+ t : ExecutionContext < Context >
71+ ) => Promise < T > ;
72+
6173export interface TestInterface <
6274 Context
6375> /*extends Omit<AvaTestInterface<Context>, 'before' | 'beforeEach' | 'after' | 'afterEach' | 'failing' | 'serial'>*/ {
6476 //#region copy-pasted from ava's .d.ts
6577 /** Declare a concurrent test. */
66- ( title : string , implementation : Implementation < Context > ) : void ;
78+ ( title : string , implementation : Implementation < unknown [ ] , Context > ) : void ;
6779 /** Declare a concurrent test that uses one or more macros. Additional arguments are passed to the macro. */
6880 < T extends any [ ] > (
6981 title : string ,
70- macros : OneOrMoreMacros < T , Context > ,
82+ implementation : Implementation < T , Context > ,
7183 ...rest : T
7284 ) : void ;
7385 /** Declare a concurrent test that uses one or more macros. The macro is responsible for generating a unique test title. */
74- < T extends any [ ] > ( macros : OneOrMoreMacros < T , Context > , ...rest : T ) : void ;
86+ < T extends any [ ] > ( macro : Implementation < T , Context > , ...rest : T ) : void ;
7587 //#endregion
7688
77- serial ( title : string , implementation : Implementation < Context > ) : void ;
89+ serial (
90+ title : string ,
91+ implementation : Implementation < unknown [ ] , Context >
92+ ) : void ;
7893 /** Declare a concurrent test that uses one or more macros. Additional arguments are passed to the macro. */
7994 serial < T extends any [ ] > (
8095 title : string ,
81- macros : OneOrMoreMacros < T , Context > ,
96+ implementation : Implementation < T , Context > ,
8297 ...rest : T
8398 ) : void ;
8499 /** Declare a concurrent test that uses one or more macros. The macro is responsible for generating a unique test title. */
85100 serial < T extends any [ ] > (
86- macros : OneOrMoreMacros < T , Context > ,
101+ implementation : Implementation < T , Context > ,
87102 ...rest : T
88103 ) : void ;
89- skip ( title : string , implementation : Implementation < Context > ) : void ;
104+ skip ( title : string , implementation : Implementation < unknown [ ] , Context > ) : void ;
90105 /** Declare a concurrent test that uses one or more macros. Additional arguments are passed to the macro. */
91106 skip < T extends any [ ] > (
92107 title : string ,
93- macros : OneOrMoreMacros < T , Context > ,
108+ implementation : Implementation < T , Context > ,
94109 ...rest : T
95110 ) : void ;
96111 /** Declare a concurrent test that uses one or more macros. The macro is responsible for generating a unique test title. */
97- skip < T extends any [ ] > ( macros : OneOrMoreMacros < T , Context > , ...rest : T ) : void ;
112+ skip < T extends any [ ] > (
113+ implementation : Implementation < T , Context > ,
114+ ...rest : T
115+ ) : void ;
98116
99117 macro < Args extends any [ ] , Ctx = Context > (
100118 cb : (
101119 ...args : Args
102120 ) =>
103- | [
104- ( ( title : string | undefined ) => string | undefined ) | string ,
105- ( t : ExecutionContext < Ctx > ) => Promise < void >
106- ]
107- | ( ( t : ExecutionContext < Ctx > ) => Promise < void > )
108- ) : AvaMacro < Args , Ctx > ;
121+ | [ SimpleTitleFn | string , SimpleImplementationFn < Ctx > ]
122+ | SimpleImplementationFn < Ctx >
123+ ) : Macro < Args , Ctx > ;
124+
125+ avaMacro : MacroFn < Context > ;
109126
110- beforeAll ( cb : ( t : ExecutionContext < Context > ) => Promise < void > ) : void ;
111- beforeEach ( cb : ( t : ExecutionContext < Context > ) => Promise < void > ) : void ;
127+ beforeAll ( cb : SimpleImplementationFn < Context > ) : void ;
128+ beforeEach ( cb : SimpleImplementationFn < Context > ) : void ;
112129 context < T extends object | void > (
113- cb : ( t : ExecutionContext < Context > ) => Promise < T >
130+ cb : SimpleContextFn < Context , T >
114131 ) : TestInterface < Context & T > ;
115132 suite ( title : string , cb : ( test : TestInterface < Context > ) => void ) : void ;
116133
@@ -125,10 +142,6 @@ export interface TestInterface<
125142
126143 // TODO add teardownEach
127144}
128- export interface AvaMacro < Args extends any [ ] = any [ ] , Ctx = unknown > {
129- ( test : ExecutionContext < Ctx > , ...args : Args ) : Promise < void > ;
130- title ?( givenTitle : string | undefined , ...args : Args ) : string ;
131- }
132145
133146function createTestInterface < Context > ( opts : {
134147 titlePrefix : string | undefined ;
@@ -145,13 +158,11 @@ function createTestInterface<Context>(opts: {
145158 let suiteOrTestDeclared = false ;
146159 function computeTitle < Args extends any [ ] > (
147160 title : string | undefined ,
148- macros ?: AvaMacro < Args , any > [ ] ,
161+ impl ?: Implementation < Args , any > ,
149162 ...args : Args
150163 ) {
151- for ( const macro of macros ?? [ ] ) {
152- if ( macro . title ) {
153- title = macro . title ( title , ...args ) ;
154- }
164+ if ( isMacroWithTitle ( impl ) ) {
165+ title = impl . title ! ( title , ...args ) ;
155166 }
156167 assert ( title ) ;
157168 // return `${ titlePrefix }${ separator }${ title }`;
@@ -165,13 +176,8 @@ function createTestInterface<Context>(opts: {
165176 function parseArgs ( args : any [ ] ) {
166177 const title =
167178 typeof args [ 0 ] === 'string' ? ( args . shift ( ) as string ) : undefined ;
168- const macros =
169- typeof args [ 0 ] === 'function'
170- ? [ args . shift ( ) as AvaMacro ]
171- : Array . isArray ( args [ 0 ] )
172- ? ( args . shift ( ) as AvaMacro [ ] )
173- : [ ] ;
174- return { title, macros, args } ;
179+ const impl = args . shift ( ) as Implementation < any [ ] , Context > ;
180+ return { title, impl, args } ;
175181 }
176182 function assertOrderingForDeclaringTest ( ) {
177183 suiteOrTestDeclared = true ;
@@ -196,29 +202,32 @@ function createTestInterface<Context>(opts: {
196202 */
197203 function declareTest (
198204 title : string | undefined ,
199- macros : AvaMacro < any [ ] , Context > [ ] ,
205+ impl : Implementation < any [ ] , Context > ,
200206 avaDeclareFunction : Function & { skip : Function } ,
201207 args : any [ ] ,
202208 skip = false
203209 ) {
204- const wrappedMacros = macros . map ( ( macro ) => {
205- return async function ( t : ExecutionContext < Context > , ...args : any [ ] ) {
206- return concurrencyLimiter (
207- errorPostprocessor ( async ( ) => {
208- let i = 0 ;
209- for ( const func of beforeEachFunctions ) {
210- await func ( t ) ;
211- i ++ ;
212- }
213- return macro ( t , ...args ) ;
214- } )
215- ) ;
216- } ;
217- } ) ;
218- const computedTitle = computeTitle ( title , macros , ...args ) ;
210+ const wrapped = async function (
211+ t : ExecutionContext < Context > ,
212+ ...args : any [ ]
213+ ) {
214+ return concurrencyLimiter (
215+ errorPostprocessor ( async ( ) => {
216+ let i = 0 ;
217+ for ( const func of beforeEachFunctions ) {
218+ await func ( t ) ;
219+ i ++ ;
220+ }
221+ return isMacro ( impl )
222+ ? impl . exec ( t , ...args )
223+ : ( impl as ImplementationFn < any [ ] , Context > ) ( t , ...args ) ;
224+ } )
225+ ) ;
226+ } ;
227+ const computedTitle = computeTitle ( title , impl , ...args ) ;
219228 ( automaticallySkip || skip ? avaDeclareFunction . skip : avaDeclareFunction ) (
220229 computedTitle ,
221- wrappedMacros ,
230+ wrapped ,
222231 ...args
223232 ) ;
224233 }
@@ -229,23 +238,23 @@ function createTestInterface<Context>(opts: {
229238 // start till it finishes.
230239 // HOWEVER if it returns a single shared state, can tests concurrently use this shared state?
231240 // if(!automaticallyDoSerial && mustDoSerial) throw new Error('Cannot declare non-serial tests because you have declared a beforeAll() hook for this test suite.');
232- const { args, macros , title } = parseArgs ( inputArgs ) ;
241+ const { args, impl , title } = parseArgs ( inputArgs ) ;
233242 return declareTest (
234243 title ,
235- macros ,
244+ impl ,
236245 automaticallyDoSerial ? avaTest . serial : avaTest ,
237246 args
238247 ) ;
239248 }
240249 test . serial = function ( ...inputArgs : any [ ] ) {
241250 assertOrderingForDeclaringTest ( ) ;
242- const { args, macros , title } = parseArgs ( inputArgs ) ;
243- return declareTest ( title , macros , avaTest . serial , args ) ;
251+ const { args, impl , title } = parseArgs ( inputArgs ) ;
252+ return declareTest ( title , impl , avaTest . serial , args ) ;
244253 } ;
245254 test . skip = function ( ...inputArgs : any [ ] ) {
246255 assertOrderingForDeclaringTest ( ) ;
247- const { args, macros , title } = parseArgs ( inputArgs ) ;
248- return declareTest ( title , macros , avaTest , args , true ) ;
256+ const { args, impl , title } = parseArgs ( inputArgs ) ;
257+ return declareTest ( title , impl , avaTest , args , true ) ;
249258 } ;
250259 test . beforeEach = function (
251260 cb : ( test : ExecutionContext < Context > ) => Promise < void >
@@ -274,27 +283,29 @@ function createTestInterface<Context>(opts: {
274283 cb : (
275284 ...args : Args
276285 ) =>
277- | [
278- ( ( title : string | undefined ) => string | undefined ) | string ,
279- ( t : ExecutionContext < Context > ) => Promise < void >
280- ]
281- | ( ( t : ExecutionContext < Context > ) => Promise < void > )
286+ | [ SimpleTitleFn | string , SimpleImplementationFn < Context > ]
287+ | SimpleImplementationFn < Context >
282288 ) {
283- function macro ( testInterface : ExecutionContext < Context > , ...args : Args ) {
284- const ret = cb ( ...args ) ;
285- const macroFunction = Array . isArray ( ret ) ? ret [ 1 ] : ret ;
286- return macroFunction ( testInterface ) ;
287- }
288- macro . title = function ( givenTitle : string | undefined , ...args : Args ) {
289+ function title ( givenTitle : string | undefined , ...args : Args ) {
289290 const ret = cb ( ...args ) ;
290291 return Array . isArray ( ret )
291292 ? typeof ret [ 0 ] === 'string'
292293 ? ret [ 0 ]
293294 : ret [ 0 ] ( givenTitle )
294- : givenTitle ;
295+ : givenTitle ?? 'UNKNOWN' ;
296+ }
297+ function exec ( testInterface : ExecutionContext < Context > , ...args : Args ) {
298+ const ret = cb ( ...args ) ;
299+ const impl = Array . isArray ( ret ) ? ret [ 1 ] : ret ;
300+ return impl ( testInterface ) ;
301+ }
302+ const declaration : MacroDeclarationOptions < Args , Context > = {
303+ title,
304+ exec,
295305 } ;
296- return macro ;
306+ return ( avaTest as TestFn < Context > ) . macro < Args > ( declaration ) ;
297307 } ;
308+ test . avaMacro = ( avaTest as TestFn < Context > ) . macro ;
298309 test . suite = function (
299310 title : string ,
300311 cb : ( test : TestInterface < Context > ) => void
@@ -322,3 +333,14 @@ function createTestInterface<Context>(opts: {
322333 } ;
323334 return test as any ;
324335}
336+
337+ function isMacro (
338+ implementation ?: Implementation < any , any >
339+ ) : implementation is Macro < any > {
340+ return implementation != null && typeof implementation !== 'function' ;
341+ }
342+ function isMacroWithTitle (
343+ implementation ?: Implementation < any , any >
344+ ) : implementation is Macro < any > {
345+ return ! ! ( implementation && ( implementation as Macro < [ ] > ) ?. title ) ;
346+ }
0 commit comments