@@ -13,18 +13,6 @@ import {
1313} from "./utils/artifacts" ;
1414import cucumberJson from "wdio-cucumberjs-json-reporter" ;
1515
16- /**
17- * Maps WebdriverIO worker IDs (cid) to their current feature bucket.
18- * A "feature bucket" is derived from the feature file name, e.g.:
19- * "register.feature" -> "register"
20- *
21- * Lifecycle:
22- * - Set in `beforeFeature`
23- * - Read in `afterStep` / `afterScenario`
24- * - Cleared in `afterFeature`
25- */
26- const FEATURE_BUCKET_BY_CID : Record < string , string > = { } ;
27-
2816export const config : WebdriverIO . Config = {
2917 ...baseConfig ,
3018
@@ -58,30 +46,7 @@ export const config: WebdriverIO.Config = {
5846 // ============
5947 // Reporters
6048 // ============
61- reporters : [
62- "spec" ,
63- // Capture execution videos via wdio-video-reporter
64- [
65- Video as any ,
66- {
67- saveAllVideos : true , // keep videos for passed and failed scenarios
68- outputDir : VIDEOS_TMP , // temp output root for MP4s this run
69- rawPath : path . join ( VIDEOS_TMP , ".video-reporter-screenshots" ) , // reporter's cached frame screenshots
70- videoFormat : "mp4" ,
71- videoSlowdownMultiplier : 1 ,
72- // Optional tuning (uncomment as needed):
73- // excludedActions: ['execute', 'keys'], // reduce noisy frames
74- // screenshotIntervalSecs: 0.75, // throttle frame capture (>= 0.5)
75- } ,
76- ] ,
77- // Write Cucumber JSON for the HTML report generator
78- [
79- "cucumberjs-json" ,
80- {
81- jsonFolder : path . join ( REPORTS_ROOT , "cucumber" ) ,
82- } ,
83- ] ,
84- ] ,
49+ reporters : [ "spec" ] ,
8550
8651 // Debug cucumber options - override base with debug settings
8752 cucumberOpts : {
@@ -103,155 +68,22 @@ export const config: WebdriverIO.Config = {
10368 /**
10469 * Gets executed once before all workers get launched.
10570 */
106- onPrepare : function ( _config , _capabilities ) {
107- const cucumberJsonDir = path . join ( REPORTS_ROOT , "cucumber" ) ;
108- const cucumberHtmlDir = path . join ( REPORTS_ROOT , "cucumber-html" ) ;
109- const videosTmpDir = VIDEOS_TMP ;
110- const videosDir = path . dirname ( videosTmpDir ) ;
111- const framesRootDir = path . join (
112- videosTmpDir ,
113- ".video-reporter-screenshots" ,
114- ) ;
115-
116- // Ensure a clean Cucumber JSON output directory for this run
117- try {
118- fs . rmSync ( cucumberJsonDir , { recursive : true , force : true } ) ;
119- } catch { }
120- fs . mkdirSync ( cucumberJsonDir , { recursive : true } ) ;
121-
122- // Clean Cucumber HTML directory
123- try {
124- fs . rmSync ( cucumberHtmlDir , { recursive : true , force : true } ) ;
125- } catch { }
126- fs . mkdirSync ( cucumberHtmlDir , { recursive : true } ) ;
127-
128- // Always start with a fresh test-videos tree
129- try {
130- fs . rmSync ( videosDir , { recursive : true , force : true } ) ;
131- } catch { }
132- fs . mkdirSync ( videosDir , { recursive : true } ) ;
133-
134- // Recreate the temp area used by wdio-video-reporter
135- fs . mkdirSync ( videosTmpDir , { recursive : true } ) ;
136- fs . mkdirSync ( framesRootDir , { recursive : true } ) ;
137- } ,
71+ onPrepare : function ( _config , _capabilities ) { } ,
13872
13973 // Remember the current feature "bucket" for this worker (cid).
140- beforeFeature : function ( uri : string ) {
141- const cid =
142- process . env . WDIO_WORKER_ID || ( browser as any ) ?. config ?. cid || "" ;
143-
144- // Derive a stable bucket name from the feature file name
145- try {
146- const filename = path . basename ( uri ) ;
147- const bucket = filename . replace ( / \. f e a t u r e $ / i, "" ) ;
148- FEATURE_BUCKET_BY_CID [ cid ] = bucket || "feature" ;
149- } catch {
150- FEATURE_BUCKET_BY_CID [ cid ] = "feature" ;
151- }
152- } ,
74+ beforeFeature : function ( uri : string ) { } ,
15375
15476 /**
15577 * After each Cucumber step, capture and attach a screenshot if the step failed.
15678 */
157- afterStep : async function ( _step , _scenario , result , context ) {
158- if ( result . passed ) return ;
159-
160- // Grab a PNG screenshot and attach it to the Cucumber JSON
161- const screenshotB64 = await browser . takeScreenshot ( ) ;
162- // @ts -ignore
163- cucumberJson . attach ( screenshotB64 , "image/png" ) ;
164-
165- // Derive the feature "bucket" recorded for this worker
166- const world = context as unknown as {
167- gherkinDocument ?: { feature ?: { name ?: string } } ;
168- pickle ?: { name ?: string } ;
169- } ;
170-
171- const cid =
172- process . env . WDIO_WORKER_ID || ( browser as any ) ?. config ?. cid || "" ;
173- const featureBucket =
174- FEATURE_BUCKET_BY_CID [ cid ] ||
175- world . gherkinDocument ?. feature ?. name ||
176- "feature" ;
177-
178- const scenarioName = world . pickle ?. name ?? _scenario ?. name ?? "scenario" ;
179- const { base, screenshots } = scenarioDirs ( featureBucket , scenarioName ) ;
180-
181- // Persist a single failure image in the scenario folder
182- fs . writeFileSync (
183- path . join ( screenshots , `${ Date . now ( ) } -failed-step.png` ) ,
184- Buffer . from ( screenshotB64 , "base64" ) ,
185- ) ;
186-
187- // Remove any legacy logs folder
188- try {
189- fs . rmSync ( path . join ( base , "logs" ) , { recursive : true , force : true } ) ;
190- } catch { }
191- } ,
192-
193- /**
194- * After each Cucumber scenario:
195- * - Move the recorded MP4 for this worker into the scenario's folder.
196- * - Remove the temporary frame screenshots.
197- * - Attach an HTML <video> player to the Cucumber JSON.
198- */
199- afterScenario : async function ( world , result , context ) {
200- const cid =
201- process . env . WDIO_WORKER_ID || ( browser as any ) ?. config ?. cid || "" ;
202- const featureBucket =
203- FEATURE_BUCKET_BY_CID [ cid ] ||
204- world . gherkinDocument ?. feature ?. name ||
205- "feature" ;
206-
207- const scenarioName = world . pickle ?. name ?? "scenario" ;
208- const { base } = scenarioDirs ( featureBucket , scenarioName ) ;
209-
210- // Move the MP4 produced by wdio-video-reporter
211- const srcVideo = cid ? findVideoForCid ( cid ) : null ;
212-
213- let videoRelPath = "" ;
214- if ( srcVideo ) {
215- const destVideo = path . join ( base , "run.mp4" ) ;
216- // Overwrite any stale file
217- try {
218- if ( fs . existsSync ( destVideo ) ) fs . rmSync ( destVideo , { force : true } ) ;
219- } catch { }
79+ afterStep : async function ( _step , _scenario , result , context ) { } ,
22080
221- fs . renameSync ( srcVideo , destVideo ) ;
222-
223- // Path relative to report output
224- videoRelPath = path
225- . relative ( path . join ( REPORTS_ROOT , "cucumber-html" ) , destVideo )
226- . split ( path . sep )
227- . join ( "/" ) ;
228- }
229-
230- // Remove any legacy logs folder
231- try {
232- fs . rmSync ( path . join ( base , "logs" ) , { recursive : true , force : true } ) ;
233- } catch { }
234-
235- // Attach a <video> player to the Cucumber JSON
236- try {
237- const html = videoRelPath
238- ? `<details><summary>Scenario video</summary><video controls width="880" src="${ videoRelPath } "></video></details>`
239- : `<em>No video found</em>` ;
240- // @ts -ignore
241- await context . attach ( html , "text/html" ) ;
242- } catch { }
243- } ,
81+ afterScenario : async function ( world , result , context ) { } ,
24482
24583 /**
24684 * Clear the worker's cached feature bucket after each feature.
24785 */
248- afterFeature : function ( _uri : string , _feature ) : void {
249- const cid =
250- process . env . WDIO_WORKER_ID || ( browser as any ) ?. config ?. cid || "" ;
251- if ( cid ) {
252- delete FEATURE_BUCKET_BY_CID [ cid ] ;
253- }
254- } ,
86+ afterFeature : function ( _uri : string , _feature ) : void { } ,
25587
25688 /**
25789 * Gets executed after all tests are done.
0 commit comments