From 743a77dc192b0cc00483e9b46484d9403a368338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Smyrek?= Date: Wed, 3 Jun 2026 14:37:00 +0200 Subject: [PATCH 1/3] Refactored tests to fix OS-related path handling. --- .../tests/utils/parallelworker.js | 15 +++++++-------- .../tests/utils/automated-tests/getkarmaconfig.js | 2 +- .../tests/utils/manual-tests/copyassets.js | 4 ++-- .../tests/utils/manual-tests/createserver.js | 4 +++- .../tests/servetranslations.js | 4 ++-- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/ckeditor5-dev-release-tools/tests/utils/parallelworker.js b/packages/ckeditor5-dev-release-tools/tests/utils/parallelworker.js index aae303e51..bf2a40912 100644 --- a/packages/ckeditor5-dev-release-tools/tests/utils/parallelworker.js +++ b/packages/ckeditor5-dev-release-tools/tests/utils/parallelworker.js @@ -30,17 +30,16 @@ vi.mock( 'node:worker_threads', () => ( { describe( 'parallelWorker (worker defined in executeInParallel())', () => { it( 'should execute a module from specified path and pass a package path and task options as arguments', async () => { + const postMessage = vi.mocked( parentPort ).postMessage; + await import( '../../lib/utils/parallelworker.js' ); - // It's needed because `parallelworker` does not export anything. Instead, it processes - // an asynchronous loop. We must wait until the current JavaScript loop ends. Adding a new promise at the end - // forces it. - await new Promise( resolve => { - setTimeout( resolve, 100 ); - } ); + // Importing the worker starts async work, so wait until it reports completion. + await vi.waitFor( () => { + expect( postMessage ).toHaveBeenCalledTimes( 2 ); + expect( postMessage ).toHaveBeenCalledWith( 'done:package' ); + }, { timeout: 1000 } ); - expect( vi.mocked( parentPort ).postMessage ).toHaveBeenCalledTimes( 2 ); - expect( vi.mocked( parentPort ).postMessage ).toHaveBeenCalledWith( 'done:package' ); expect( vi.mocked( virtual ) ).toHaveBeenCalledTimes( 2 ); expect( vi.mocked( virtual ) ).toHaveBeenCalledWith( '/home/ckeditor/packages/a', taskOptions ); expect( vi.mocked( virtual ) ).toHaveBeenCalledWith( '/home/ckeditor/packages/b', taskOptions ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js index f9d5a4fa8..55b8c70b4 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js +++ b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js @@ -119,7 +119,7 @@ describe( 'getKarmaConfig()', () => { expect( karmaConfig.files ).toEqual( expect.arrayContaining( [ 'workspace/entry-file.js', expect.objectContaining( { - pattern: expect.stringContaining( 'ckeditor5-utils/tests/_assets/**/*' ) + pattern: expect.stringMatching( /ckeditor5-utils[/\\]tests[/\\]_assets[/\\]\*\*[/\\]\*/ ) } ) ] ) ); } ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/copyassets.js b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/copyassets.js index 4bb12d9c7..5383c71c1 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/copyassets.js +++ b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/copyassets.js @@ -31,7 +31,7 @@ describe( 'copyAssets()', () => { const buildDir = '/build'; copyAssets( buildDir ); - expect( mkdirSync ).toHaveBeenCalledWith( buildDir + '/assets', expect.any( Object ) ); + expect( mkdirSync ).toHaveBeenCalledWith( path.join( buildDir, 'assets' ), expect.any( Object ) ); expect( copyFileSync ).toHaveBeenCalledTimes( ASSETS.length + 1 ); const scriptPath = path.resolve( import.meta.dirname, '..', '..', '..', 'lib', 'utils', 'manual-tests' ); @@ -40,7 +40,7 @@ describe( 'copyAssets()', () => { expect( copyFileSync ).toHaveBeenNthCalledWith( index + 1, path.resolve( scriptPath, assetPath ), - path.resolve( buildDir, 'assets', path.basename( assetPath ) ) + path.join( buildDir, 'assets', path.basename( assetPath ) ) ); } } ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js index e67bf8cb8..4dc87f18b 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js +++ b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js @@ -31,6 +31,8 @@ describe( 'createManualTestServer()', () => { info: loggerStub } ); + vi.spyOn( process, 'platform', 'get' ).mockReturnValue( 'linux' ); + vi.spyOn( http, 'createServer' ).mockImplementation( ( ...theArgs ) => { server = createServer( ...theArgs ); servers.push( server ); @@ -160,7 +162,7 @@ describe( 'createManualTestServer()', () => { describe( 'request handler', () => { beforeEach( async () => { - createManualTestServer( 'workspace/build/.manual-tests', 49800 ); + createManualTestServer( 'workspace/build/.manual-tests', 49700 ); await vi.waitFor( () => { expect( loggerStub ).toHaveBeenCalled(); diff --git a/packages/ckeditor5-dev-translations/tests/servetranslations.js b/packages/ckeditor5-dev-translations/tests/servetranslations.js index 3dbd4ad98..67e1612f1 100644 --- a/packages/ckeditor5-dev-translations/tests/servetranslations.js +++ b/packages/ckeditor5-dev-translations/tests/servetranslations.js @@ -30,7 +30,7 @@ describe( 'serveTranslations()', () => { let cwdSpy; beforeEach( () => { - cwdSpy = vi.spyOn( process, 'cwd' ).mockReturnValue( '/project' ); + cwdSpy = vi.spyOn( process, 'cwd' ).mockReturnValue( path.join( path.sep, 'project' ) ); vi.mocked( fs.existsSync ).mockReturnValue( false ); vi.mocked( fs.readFileSync ).mockReset(); vi.mocked( rimraf.sync ).mockReset(); @@ -141,7 +141,7 @@ describe( 'serveTranslations()', () => { expect( module.loaders[ 0 ].options.translateSource( 'SOURCE', 'file.ts' ) ).to.equal( 'translated:file.ts' ); expect( translationService.translateSource ).toHaveBeenCalledWith( 'SOURCE', 'file.ts' ); expect( - translationService.loadPackage.mock.calls.some( call => String( call[ 0 ] ).includes( 'packages/ckeditor5-foo/' ) ) + translationService.loadPackage.mock.calls.some( call => /packages[/\\]ckeditor5-foo[/\\]/.test( String( call[ 0 ] ) ) ) ).to.equal( true ); compilation.hooks.optimizeChunkAssets.call( [ { files: [ 'main.js', 'other.js' ] } ] ); From 25d65aa410d482202d5ea27a9363d10478f9146d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Smyrek?= Date: Fri, 5 Jun 2026 07:52:57 +0200 Subject: [PATCH 2/3] Stop binding real webserver sockets in the unit tests. --- .../tests/utils/manual-tests/createserver.js | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js index 4dc87f18b..9a127bad3 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js +++ b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/createserver.js @@ -37,7 +37,11 @@ describe( 'createManualTestServer()', () => { server = createServer( ...theArgs ); servers.push( server ); - vi.spyOn( server, 'listen' ); + vi.spyOn( server, 'listen' ).mockImplementation( ( _port, callback ) => { + process.nextTick( callback ); + + return server; + } ); return server; } ); @@ -123,11 +127,28 @@ describe( 'createManualTestServer()', () => { } ); it( 'should try next port when the requested port is in use', async () => { - // Occupy the port first. - const blockingServer = http.createServer.getMockImplementation()(); + const originalCreateServer = http.createServer.getMockImplementation(); + let attempt = 0; + + vi.mocked( http.createServer ).mockImplementation( ( ...args ) => { + const currentServer = originalCreateServer( ...args ); + + attempt++; - await new Promise( resolve => { - blockingServer.listen( 49555, resolve ); + if ( attempt === 1 ) { + vi.mocked( currentServer.listen ).mockImplementation( () => { + process.nextTick( () => { + const error = new Error( 'EADDRINUSE: port is already in use' ); + error.code = 'EADDRINUSE'; + + currentServer.emit( 'error', error ); + } ); + + return currentServer; + } ); + } + + return currentServer; } ); createManualTestServer( 'workspace/build/.manual-tests', 49555 ); @@ -136,9 +157,9 @@ describe( 'createManualTestServer()', () => { expect( loggerStub ).toHaveBeenCalledWith( '[Server] Server running at http://localhost:49556/' ); } ); + expect( servers[ 0 ].listen ).toHaveBeenCalledWith( 49555, expect.any( Function ) ); + expect( servers[ 1 ].listen ).toHaveBeenCalledWith( 49556, expect.any( Function ) ); expect( loggerStub ).toHaveBeenCalledWith( '[Server] Port 49555 is in use, trying 49556...' ); - - blockingServer.close(); } ); it( 'should reject when a non-EADDRINUSE error occurs', async () => { From 91dad47ab8419556105d85a3f35c4a92e08cf5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Smyrek?= Date: Fri, 5 Jun 2026 11:47:02 +0200 Subject: [PATCH 3/3] Simplified tests. --- .../tests/utils/automated-tests/getkarmaconfig.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js index 55b8c70b4..ee8fa5780 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js +++ b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js @@ -8,18 +8,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import getWebpackConfigForAutomatedTests from '../../../lib/utils/automated-tests/getwebpackconfig.js'; import getKarmaConfig from '../../../lib/utils/automated-tests/getkarmaconfig.js'; -vi.mock( 'node:path', async () => { - const originalModule = await vi.importActual( 'node:path' ); - - return { - default: { - join: vi.fn( ( ...chunks ) => chunks.join( '/' ) ), - dirname: vi.fn(), - resolve: originalModule.resolve - } - }; -} ); - vi.mock( '../../../lib/utils/automated-tests/getwebpackconfig.js' ); vi.mock( '../../../lib/utils/resolve-path.js', () => ( { @@ -119,7 +107,7 @@ describe( 'getKarmaConfig()', () => { expect( karmaConfig.files ).toEqual( expect.arrayContaining( [ 'workspace/entry-file.js', expect.objectContaining( { - pattern: expect.stringMatching( /ckeditor5-utils[/\\]tests[/\\]_assets[/\\]\*\*[/\\]\*/ ) + pattern: expect.stringContaining( path.join( 'ckeditor5-utils', 'tests', '_assets', '**', '*' ) ) } ) ] ) ); } );