1- import type { TestCase , TestCaseExecution } from './domain'
1+ import type { TestCase , TestCaseExecution , TestCasePhases } from './domain'
22import { debug , retry } from './utils.js'
33import { dirname } from 'node:path'
44import test from 'node:test'
@@ -22,8 +22,8 @@ export const defaultPlugins = [
2222 './plugins/http-mock-plugin.js' ,
2323]
2424
25- const preparePluginFunction =
26- ( plugins : any [ ] , basePath : string , testRunnerArgs ?: unknown ) => async ( functionName : string , data : unknown ) => {
25+ const createPluginExecutor = ( plugins : any [ ] , basePath : string , testRunnerArgs ?: unknown ) => {
26+ return async ( functionName : string , data : unknown ) => {
2727 if ( ! data ) {
2828 return
2929 }
@@ -41,21 +41,64 @@ const preparePluginFunction =
4141 throw new Error ( `No actions (${ functionName } ) executed` )
4242 }
4343 }
44+ }
45+
46+ const createPhaseExecutor = (
47+ executePluginFunction : ( functionName : string , data : unknown ) => Promise < void > ,
48+ testCaseExecution : TestCaseExecution ,
49+ ) => {
50+ const allowedLayerPhases = [ 'arrange' , 'clean' ]
51+
52+ const executePhase = async ( phase : TestCasePhases , testCase : TestCase ) => {
53+ if ( ! testCase [ phase ] ) {
54+ return
55+ }
56+
57+ if ( phase === 'assert' ) {
58+ await retry ( ( ) => executePluginFunction ( phase , testCase [ phase ] ) , testCase . retry , testCase . delay )
59+ } else {
60+ await executePluginFunction ( phase , testCase [ phase ] )
61+ }
62+ }
63+
64+ const executeLayerPhase = async ( phase : TestCasePhases , layers : TestCase [ ] ) => {
65+ await Promise . all (
66+ layers
67+ . filter ( ( layer ) => layer [ phase ] )
68+ . map ( ( layer ) => executePhase ( phase , layer ) )
69+ )
70+ }
71+
72+ const execute = async ( phase : TestCasePhases ) => {
73+ if ( testCaseExecution . resolvedLayers && allowedLayerPhases . includes ( phase ) ) {
74+ await executeLayerPhase ( phase , testCaseExecution . resolvedLayers )
75+ }
76+
77+ await executePhase ( phase , testCaseExecution . testCase )
78+ }
79+
80+ return { execute }
81+ }
4482
45- const runSafe = (
83+ const createTestCaseExecutor = async (
4684 testCaseExecution : TestCaseExecution ,
47- executePluginFunction : ( functionName : string , data : unknown ) => Promise < void >
85+ plugins : string [ ] ,
86+ testRunnerArgs ?: unknown ,
4887) => {
88+ const basePath = dirname ( testCaseExecution . filePath )
89+ const loadedPlugins = await Promise . all ( plugins . map ( ( plugin ) => import ( plugin ) ) )
90+ const executePluginFunction = createPluginExecutor ( loadedPlugins , basePath , testRunnerArgs )
91+ const phaseExecutor = createPhaseExecutor ( executePluginFunction , testCaseExecution )
4992 let errors : Error [ ] = [ ]
5093
51- const step = async ( step : string , testCase : TestCase ) => {
94+ const execute = async ( phase : TestCasePhases ) => {
5295 try {
53- if ( ! testCase [ step ] || ( errors . length > 0 && step !== 'clean' ) ) {
96+ if ( errors . length > 0 && phase !== 'clean' ) {
5497 return
5598 }
56- await executePluginFunction ( step , testCase [ step ] )
99+ await phaseExecutor . execute ( phase )
57100 } catch ( err : any ) {
58- err . name = `${ step . charAt ( 0 ) . toUpperCase ( ) + step . slice ( 1 ) } Error`
101+ err . name = `${ phase . charAt ( 0 ) . toUpperCase ( ) + phase . slice ( 1 ) } Error`
59102 errors . push ( err )
60103 debug ( `${ err . name } : ${ err . message } \n${ err . stack } ` )
61104 }
@@ -70,10 +113,9 @@ const runSafe = (
70113 }
71114 }
72115
73- return { step , throwIfError }
116+ return { execute , throwIfError }
74117}
75118
76-
77119export const executeTestCase = async (
78120 testCaseExecution : TestCaseExecution ,
79121 plugins : string [ ] ,
@@ -83,32 +125,12 @@ export const executeTestCase = async (
83125 debug ( `TestRunnerArgs: ${ JSON . stringify ( testRunnerArgs , null , 2 ) } ` )
84126 debug ( `Plugins: ${ JSON . stringify ( plugins , null , 2 ) } ` )
85127
86- const basePath = dirname ( testCaseExecution . filePath )
87-
88- const loadedPlugins = await Promise . all ( plugins . map ( ( plugin ) => import ( plugin ) ) )
89- const executePluginFunction = preparePluginFunction ( loadedPlugins , basePath , testRunnerArgs )
90- const testCase = testCaseExecution . testCase
91- const { step, throwIfError } = runSafe ( testCaseExecution , executePluginFunction )
92-
93- if ( testCaseExecution . resolvedLayers ) {
94- await Promise . all (
95- testCaseExecution . resolvedLayers . filter ( ( v ) => v . arrange ) . map ( ( v ) => step ( 'arrange' , v ) ) ,
96- )
97- }
98-
99- await step ( 'arrange' , testCase )
100-
101- await step ( 'act' , testCase )
102-
103- await retry ( ( ) => step ( 'assert' , testCase ) , testCase . retry , testCase . delay )
128+ const executor = await createTestCaseExecutor ( testCaseExecution , plugins , testRunnerArgs )
129+ const phases : TestCasePhases [ ] = [ 'arrange' , 'act' , 'assert' , 'clean' ]
104130
105- await step ( 'clean' , testCase )
106-
107- if ( testCaseExecution . resolvedLayers ) {
108- await Promise . all (
109- testCaseExecution . resolvedLayers . filter ( ( v ) => v . clean ) . map ( ( v ) => step ( 'clean' , v ) ) ,
110- )
131+ for ( const phase of phases ) {
132+ await executor . execute ( phase )
111133 }
112134
113- throwIfError ( )
135+ executor . throwIfError ( )
114136}
0 commit comments