1- /* eslint-disable @typescript-eslint/no-unsafe-argument */
21import assert from 'assert' ;
32import { EOL } from 'os' ;
43import path from 'path' ;
54import { anything , instance , mock , reset , spy , when } from 'ts-mockito' ;
6- import { TestItem , TestItemCollection , TestMessage , TestRun , Uri , workspace } from 'vscode' ;
5+ import {
6+ TestController ,
7+ TestItem ,
8+ TestItemCollection ,
9+ TestMessage ,
10+ TestRun ,
11+ Uri ,
12+ workspace ,
13+ } from 'vscode' ;
714import { CancellationTokenSource } from 'vscode-languageclient' ;
815import * as e3 from '../../src/e3Testsuite' ;
916import { activate } from '../utils' ;
1017
18+ /**
19+ * Interface for capturing test execution results
20+ */
21+ interface TestResults {
22+ enqueued : string [ ] ;
23+ started : string [ ] ;
24+ passed : string [ ] ;
25+ failed : { id : string ; message : TestMessage [ ] } [ ] ;
26+ errors : { id : string ; message : TestMessage [ ] } [ ] ;
27+ }
28+
29+ /**
30+ * Class for managing mocking setup with mutable state
31+ */
32+ class MockSetup {
33+ public spyCtrl : TestController ;
34+ public mockRun : TestRun ;
35+ public consoleOutput : string = '' ;
36+ public results ?: TestResults ;
37+
38+ constructor ( mode : 'basic' | 'full' = 'basic' ) {
39+ this . spyCtrl = spy ( e3 . controller ) ;
40+ const mockRun = mock < TestRun > ( ) ;
41+
42+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
43+
44+ // Console output capture (common to both modes)
45+ when ( mockRun . appendOutput ( anything ( ) ) ) . thenCall ( ( output : string ) => {
46+ this . consoleOutput += output . replace ( / ( \r + \n | \n \r + ) / g, '\n' ) ;
47+ } ) ;
48+
49+ // Set up test result capture for full mode
50+ if ( mode === 'full' ) {
51+ const enqueued : string [ ] = [ ] ;
52+ const started : string [ ] = [ ] ;
53+ const passed : string [ ] = [ ] ;
54+ const failed : { id : string ; message : TestMessage [ ] } [ ] = [ ] ;
55+ const errors : { id : string ; message : TestMessage [ ] } [ ] = [ ] ;
56+
57+ when ( mockRun . enqueued ( anything ( ) ) ) . thenCall ( ( item : TestItem ) => {
58+ enqueued . push ( item . id ) ;
59+ } ) ;
60+ when ( mockRun . started ( anything ( ) ) ) . thenCall ( ( item : TestItem ) => {
61+ started . push ( item . id ) ;
62+ } ) ;
63+ when ( mockRun . passed ( anything ( ) ) ) . thenCall ( ( item : TestItem ) => {
64+ passed . push ( item . id ) ;
65+ } ) ;
66+ when ( mockRun . failed ( anything ( ) , anything ( ) ) ) . thenCall (
67+ ( item : TestItem , message ?: TestMessage | TestMessage [ ] ) => {
68+ let messages : TestMessage [ ] = [ ] ;
69+ if ( Array . isArray ( message ) ) {
70+ messages = message ;
71+ } else if ( message ) {
72+ messages = [ message ] ;
73+ }
74+ failed . push ( { id : item . id , message : messages } ) ;
75+ } ,
76+ ) ;
77+ when ( mockRun . errored ( anything ( ) , anything ( ) ) ) . thenCall (
78+ ( item : TestItem , message ?: TestMessage | TestMessage [ ] ) => {
79+ let messages : TestMessage [ ] = [ ] ;
80+ if ( Array . isArray ( message ) ) {
81+ messages = message ;
82+ } else if ( message ) {
83+ messages = [ message ] ;
84+ }
85+ errors . push ( { id : item . id , message : messages } ) ;
86+ } ,
87+ ) ;
88+
89+ this . results = {
90+ enqueued,
91+ started,
92+ passed,
93+ failed,
94+ errors,
95+ } ;
96+ }
97+
98+ // Create the mock run instance and set up spy controller mappings
99+ this . mockRun = instance ( mockRun ) ;
100+ when ( this . spyCtrl . createTestRun ( anything ( ) ) ) . thenReturn ( this . mockRun ) ;
101+ when ( this . spyCtrl . createTestRun ( anything ( ) , anything ( ) ) ) . thenReturn ( this . mockRun ) ;
102+ when ( this . spyCtrl . createTestRun ( anything ( ) , anything ( ) , anything ( ) ) ) . thenReturn (
103+ this . mockRun ,
104+ ) ;
105+
106+ /* eslint-enable @typescript-eslint/no-unsafe-argument */
107+ }
108+
109+ /**
110+ * Cleans up mocking after test execution
111+ */
112+ cleanup ( ) : void {
113+ reset ( this . spyCtrl ) ;
114+ }
115+ }
116+
11117suite ( 'e3-testsuite' , function ( ) {
12118 this . beforeAll ( async function ( ) {
13119 await activate ( ) ;
@@ -64,20 +170,8 @@ suite('e3-testsuite', function () {
64170 test ( 'Test list after run' , async function ( ) {
65171 await e3 . controller . refreshHandler ! ( new CancellationTokenSource ( ) . token ) ;
66172
67- const spyCtrl = spy ( e3 . controller ) ;
173+ const mockSetup = new MockSetup ( 'basic' ) ;
68174 try {
69- const mockRun = mock < TestRun > ( ) ;
70- let consoleOutput = '' ;
71- when ( mockRun . appendOutput ( anything ( ) ) ) . thenCall ( ( output : string ) => {
72- consoleOutput += output . replace ( / ( \r + \n | \n \r + ) / g, '\n' ) ;
73- } ) ;
74-
75- const run = instance ( mockRun ) ;
76-
77- when ( spyCtrl . createTestRun ( anything ( ) ) ) . thenReturn ( run ) ;
78- when ( spyCtrl . createTestRun ( anything ( ) , anything ( ) ) ) . thenReturn ( run ) ;
79- when ( spyCtrl . createTestRun ( anything ( ) , anything ( ) , anything ( ) ) ) . thenReturn ( run ) ;
80-
81175 await e3 . runHandler (
82176 { include : undefined , exclude : undefined , profile : undefined } ,
83177 new CancellationTokenSource ( ) . token ,
@@ -211,75 +305,28 @@ suite('e3-testsuite', function () {
211305 // Include console output in the error message for debugging
212306 const errorMessage =
213307 `Test structure assertion failed.\n\n` +
214- `Console output:\n${ consoleOutput } \n\n` +
308+ `Console output:\n${ mockSetup . consoleOutput } \n\n` +
215309 `Original error:\n${ String ( error ) } ` ;
216310 throw new Error ( errorMessage ) ;
217311 }
218312 } finally {
219- reset ( spyCtrl ) ;
313+ mockSetup . cleanup ( ) ;
220314 }
221315 } ) ;
222316
223317 test ( 'Capturing test results' , async function ( ) {
224318 await e3 . controller . refreshHandler ! ( new CancellationTokenSource ( ) . token ) ;
225319
226- const spyCtrl = spy ( e3 . controller ) ;
320+ const mockSetup = new MockSetup ( 'full' ) ;
227321 try {
228- const mockRun = mock < TestRun > ( ) ;
229- let consoleOutput = '' ;
230- when ( mockRun . appendOutput ( anything ( ) ) ) . thenCall ( ( output : string ) => {
231- consoleOutput += output . replace ( / ( \r + \n | \n \r + ) / g, '\n' ) ;
232- } ) ;
233-
234- const enqueued : string [ ] = [ ] ;
235- const started : string [ ] = [ ] ;
236- const passed : string [ ] = [ ] ;
237- const failed : { id : string ; message : TestMessage [ ] } [ ] = [ ] ;
238- const errors : { id : string ; message : TestMessage [ ] } [ ] = [ ] ;
239-
240- when ( mockRun . enqueued ( anything ( ) ) ) . thenCall ( ( item : TestItem ) => {
241- enqueued . push ( item . id ) ;
242- } ) ;
243- when ( mockRun . started ( anything ( ) ) ) . thenCall ( ( item : TestItem ) => {
244- started . push ( item . id ) ;
245- } ) ;
246- when ( mockRun . passed ( anything ( ) ) ) . thenCall ( ( item : TestItem ) => {
247- passed . push ( item . id ) ;
248- } ) ;
249- when ( mockRun . failed ( anything ( ) , anything ( ) ) ) . thenCall (
250- ( item : TestItem , message ?: TestMessage | TestMessage [ ] ) => {
251- let messages : TestMessage [ ] = [ ] ;
252- if ( Array . isArray ( message ) ) {
253- messages = message ;
254- } else if ( message ) {
255- messages = [ message ] ;
256- }
257- failed . push ( { id : item . id , message : messages } ) ;
258- } ,
259- ) ;
260- when ( mockRun . errored ( anything ( ) , anything ( ) ) ) . thenCall (
261- ( item : TestItem , message ?: TestMessage | TestMessage [ ] ) => {
262- let messages : TestMessage [ ] = [ ] ;
263- if ( Array . isArray ( message ) ) {
264- messages = message ;
265- } else if ( message ) {
266- messages = [ message ] ;
267- }
268- errors . push ( { id : item . id , message : messages } ) ;
269- } ,
270- ) ;
271-
272- const run = instance ( mockRun ) ;
273-
274- when ( spyCtrl . createTestRun ( anything ( ) ) ) . thenReturn ( run ) ;
275- when ( spyCtrl . createTestRun ( anything ( ) , anything ( ) ) ) . thenReturn ( run ) ;
276- when ( spyCtrl . createTestRun ( anything ( ) , anything ( ) , anything ( ) ) ) . thenReturn ( run ) ;
277-
278322 await e3 . runHandler (
279323 { include : undefined , exclude : undefined , profile : undefined } ,
280324 new CancellationTokenSource ( ) . token ,
281325 ) ;
282326
327+ const consoleOutput = mockSetup . consoleOutput ;
328+ const { enqueued, started, passed, failed, errors } = mockSetup . results ! ;
329+
283330 const workspaceRoot = workspace . workspaceFolders ! [ 0 ] . uri . fsPath ;
284331 const testsuitePath = `${ workspaceRoot } ${ path . sep } testsuite.py` ;
285332 const pythonPathRegex =
@@ -405,7 +452,7 @@ suite('e3-testsuite', function () {
405452 ] ) ;
406453 assert . deepStrictEqual ( errors , [ ] ) ;
407454 } finally {
408- reset ( spyCtrl ) ;
455+ mockSetup . cleanup ( ) ;
409456 }
410457 } ) ;
411458
@@ -421,26 +468,15 @@ suite('e3-testsuite', function () {
421468 const testArgs = [ '--verbose' , '--show-time-info' ] ;
422469 await config . update ( 'args' , testArgs , false ) ;
423470
424- const spyCtrl = spy ( e3 . controller ) ;
471+ const mockSetup = new MockSetup ( 'basic' ) ;
425472 try {
426- const mockRun = mock < TestRun > ( ) ;
427- let consoleOutput = '' ;
428- when ( mockRun . appendOutput ( anything ( ) ) ) . thenCall ( ( output : string ) => {
429- consoleOutput += output . replace ( / ( \r + \n | \n \r + ) / g, '\n' ) ;
430- } ) ;
431-
432- const run = instance ( mockRun ) ;
433-
434- when ( spyCtrl . createTestRun ( anything ( ) ) ) . thenReturn ( run ) ;
435- when ( spyCtrl . createTestRun ( anything ( ) , anything ( ) ) ) . thenReturn ( run ) ;
436- when ( spyCtrl . createTestRun ( anything ( ) , anything ( ) , anything ( ) ) ) . thenReturn ( run ) ;
437-
438473 // Run the handler
439474 await e3 . runHandler (
440475 { include : undefined , exclude : undefined , profile : undefined } ,
441476 new CancellationTokenSource ( ) . token ,
442477 ) ;
443478
479+ const consoleOutput = mockSetup . consoleOutput ;
444480 // Check that the custom args appear in the console output
445481 assert . ok (
446482 consoleOutput . includes ( '--verbose' ) ,
@@ -471,7 +507,7 @@ suite('e3-testsuite', function () {
471507 `Expected '--show-time-info' not found in command: ${ commandLine } ` ,
472508 ) ;
473509 } finally {
474- reset ( spyCtrl ) ;
510+ mockSetup . cleanup ( ) ;
475511 }
476512 } finally {
477513 // Always restore original configuration
0 commit comments