From 0b867f627d45f6fe50dc8cd9feb04f2df31b8f37 Mon Sep 17 00:00:00 2001 From: Marcin Panek Date: Wed, 29 Jan 2025 15:41:53 +0100 Subject: [PATCH 1/3] Fixed automated tests entry point on Windows. --- .../lib/tasks/runautomatedtests.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js index 4c01c0371..50ef58327 100644 --- a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js +++ b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js @@ -4,7 +4,6 @@ */ import fs from 'fs'; -import path from 'path'; import { fileURLToPath } from 'url'; import { logger } from '@ckeditor/ckeditor5-dev-utils'; import getKarmaConfig from '../utils/automated-tests/getkarmaconfig.js'; @@ -15,21 +14,22 @@ import { mkdirp } from 'mkdirp'; import karmaLogger from 'karma/lib/logger.js'; import karma from 'karma'; import transformFileOptionToTestGlob from '../utils/transformfileoptiontotestglob.js'; +import upath from 'upath'; const __filename = fileURLToPath( import.meta.url ); -const __dirname = path.dirname( __filename ); +const __dirname = upath.dirname( __filename ); // Glob patterns that should be ignored. It means if a specified test file is located under path // that matches to these patterns, the file will be skipped. const IGNORE_GLOBS = [ // Ignore files which are saved in `manual/` directory. There are manual tests. - path.join( '**', 'tests', '**', 'manual', '**', '*.{js,ts}' ), + upath.join( '**', 'tests', '**', 'manual', '**', '*.{js,ts}' ), // Ignore `_utils` directory as well because there are saved utils for tests. - path.join( '**', 'tests', '**', '_utils', '**', '*.{js,ts}' ) + upath.join( '**', 'tests', '**', '_utils', '**', '*.{js,ts}' ) ]; // An absolute path to the entry file that will be passed to Karma. -const ENTRY_FILE_PATH = path.posix.join( process.cwd(), 'build', '.automated-tests', 'entry-point.js' ); +const ENTRY_FILE_PATH = upath.posix.join( process.cwd(), 'build', '.automated-tests', 'entry-point.js' ); export default function runAutomatedTests( options ) { return Promise.resolve().then( () => { @@ -68,7 +68,7 @@ function transformFilesToTestGlob( files ) { } function createEntryFile( globPatterns, production ) { - mkdirp.sync( path.dirname( ENTRY_FILE_PATH ) ); + mkdirp.sync( upath.dirname( ENTRY_FILE_PATH ) ); karmaLogger.setupFromConfig( { logLevel: 'INFO' } ); const log = karmaLogger.create( 'config' ); @@ -99,21 +99,21 @@ function createEntryFile( globPatterns, production ) { } // Set global license key in the `before` hook. - allFiles.unshift( path.join( __dirname, '..', 'utils', 'automated-tests', 'licensekeybefore.js' ).replace( /\\/g, '/' ) ); + allFiles.unshift( upath.join( __dirname, '..', 'utils', 'automated-tests', 'licensekeybefore.js' ).replace( /\\/g, '/' ) ); // Inject the leak detector root hooks. Need to be split into two parts due to #598. - allFiles.splice( 0, 0, path.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorbefore.js' ).replace( /\\/g, '/' ) ); - allFiles.push( path.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorafter.js' ).replace( /\\/g, '/' ) ); + allFiles.splice( 0, 0, upath.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorbefore.js' ).replace( /\\/g, '/' ) ); + allFiles.push( upath.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorafter.js' ).replace( /\\/g, '/' ) ); const entryFileContent = allFiles .map( file => 'import "' + file + '";' ); // Inject the custom chai assertions. See ckeditor/ckeditor5#9668. - const assertionsDir = path.join( __dirname, '..', 'utils', 'automated-tests', 'assertions' ).replace( /\\/g, '/' ); + const assertionsDir = upath.join( __dirname, '..', 'utils', 'automated-tests', 'assertions' ).replace( /\\/g, '/' ); const customAssertions = fs.readdirSync( assertionsDir ).map( assertionFileName => { return [ assertionFileName, - path.parse( assertionFileName ).name.replace( /-([a-z])/g, value => value[ 1 ].toUpperCase() ) + upath.parse( assertionFileName ).name.replace( /-([a-z])/g, value => value[ 1 ].toUpperCase() ) ]; } ); @@ -209,7 +209,7 @@ function runKarma( options ) { } ); if ( options.coverage ) { - const coveragePath = path.join( process.cwd(), 'coverage' ); + const coveragePath = upath.join( process.cwd(), 'coverage' ); server.on( 'run_complete', () => { // Use timeout to not write to the console in the middle of Karma's status. From 3bc5b336e5e90eb7da2232cf211ab1cc32ba99a1 Mon Sep 17 00:00:00 2001 From: Marcin Panek Date: Thu, 30 Jan 2025 10:51:30 +0100 Subject: [PATCH 2/3] Added `upath` to dependencies and replaced `upath.posix.join` with `upath.join`. --- .../lib/tasks/runautomatedtests.js | 12 ++++++------ packages/ckeditor5-dev-tests/package.json | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js index 50ef58327..76c30a109 100644 --- a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js +++ b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js @@ -29,7 +29,7 @@ const IGNORE_GLOBS = [ ]; // An absolute path to the entry file that will be passed to Karma. -const ENTRY_FILE_PATH = upath.posix.join( process.cwd(), 'build', '.automated-tests', 'entry-point.js' ); +const ENTRY_FILE_PATH = upath.join( process.cwd(), 'build', '.automated-tests', 'entry-point.js' ); export default function runAutomatedTests( options ) { return Promise.resolve().then( () => { @@ -78,7 +78,7 @@ function createEntryFile( globPatterns, production ) { let hasFiles = false; for ( const resolvedPattern of globPatterns[ singlePattern ] ) { - const files = globSync( resolvedPattern ).map( file => file.replace( /\\/g, '/' ) ); + const files = globSync( resolvedPattern ); if ( files.length ) { hasFiles = true; @@ -99,17 +99,17 @@ function createEntryFile( globPatterns, production ) { } // Set global license key in the `before` hook. - allFiles.unshift( upath.join( __dirname, '..', 'utils', 'automated-tests', 'licensekeybefore.js' ).replace( /\\/g, '/' ) ); + allFiles.unshift( upath.join( __dirname, '..', 'utils', 'automated-tests', 'licensekeybefore.js' ) ); // Inject the leak detector root hooks. Need to be split into two parts due to #598. - allFiles.splice( 0, 0, upath.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorbefore.js' ).replace( /\\/g, '/' ) ); - allFiles.push( upath.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorafter.js' ).replace( /\\/g, '/' ) ); + allFiles.splice( 0, 0, upath.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorbefore.js' ) ); + allFiles.push( upath.join( __dirname, '..', 'utils', 'automated-tests', 'leaksdetectorafter.js' ) ); const entryFileContent = allFiles .map( file => 'import "' + file + '";' ); // Inject the custom chai assertions. See ckeditor/ckeditor5#9668. - const assertionsDir = upath.join( __dirname, '..', 'utils', 'automated-tests', 'assertions' ).replace( /\\/g, '/' ); + const assertionsDir = upath.join( __dirname, '..', 'utils', 'automated-tests', 'assertions' ); const customAssertions = fs.readdirSync( assertionsDir ).map( assertionFileName => { return [ assertionFileName, diff --git a/packages/ckeditor5-dev-tests/package.json b/packages/ckeditor5-dev-tests/package.json index 264b40a38..7d4f70f22 100644 --- a/packages/ckeditor5-dev-tests/package.json +++ b/packages/ckeditor5-dev-tests/package.json @@ -72,6 +72,7 @@ "sinon-chai": "^3.5.0", "socket.io": "^4.0.0", "typescript": "5.0.4", + "upath": "^2.0.1", "webpack": "^5.94.0" }, "devDependencies": { From a8f4de57434b4d7ba7a7797428d3804244bb215a Mon Sep 17 00:00:00 2001 From: Marcin Panek Date: Fri, 31 Jan 2025 12:18:42 +0100 Subject: [PATCH 3/3] Fixed normalizing paths from globSync on Windows and added a test. --- .../lib/tasks/runautomatedtests.js | 2 +- .../tests/tasks/runautomatedtests.js | 51 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js index 76c30a109..b3121be8d 100644 --- a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js +++ b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js @@ -78,7 +78,7 @@ function createEntryFile( globPatterns, production ) { let hasFiles = false; for ( const resolvedPattern of globPatterns[ singlePattern ] ) { - const files = globSync( resolvedPattern ); + const files = globSync( resolvedPattern ).map( filePath => upath.normalize( filePath ) ); if ( files.length ) { hasFiles = true; diff --git a/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js b/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js index 8e2d14de7..c41e98ce9 100644 --- a/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js +++ b/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js @@ -3,7 +3,6 @@ * For licensing, see LICENSE.md. */ -import path from 'path'; import fs from 'fs'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { globSync } from 'glob'; @@ -12,6 +11,7 @@ import chalk from 'chalk'; import karma from 'karma'; import karmaLogger from 'karma/lib/logger.js'; import transformFileOptionToTestGlob from '../../lib/utils/transformfileoptiontotestglob.js'; +import upath from 'upath'; const stubs = vi.hoisted( () => ( { log: { @@ -349,7 +349,7 @@ describe( 'runAutomatedTests()', () => { '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' ] ); - const assertionsDir = path.join( __dirname, '..', '..', 'lib', 'utils', 'automated-tests', 'assertions' ).replace( /\\/g, '/' ); + const assertionsDir = upath.join( __dirname, '..', '..', 'lib', 'utils', 'automated-tests', 'assertions' ); const expectedEntryPointContent = [ `import assertionAFactory from "${ assertionsDir }/assertionA.js";`, @@ -400,7 +400,7 @@ describe( 'runAutomatedTests()', () => { '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' ] ); - const assertionsDir = path.join( __dirname, '..', '..', 'lib', 'utils', 'automated-tests', 'assertions' ).replace( /\\/g, '/' ); + const assertionsDir = upath.join( __dirname, '..', '..', 'lib', 'utils', 'automated-tests', 'assertions' ); const expectedEntryPointContent = [ `import assertionAFactory from "${ assertionsDir }/assertion-a.js";`, @@ -429,4 +429,49 @@ describe( 'runAutomatedTests()', () => { expect.stringContaining( expectedEntryPointContent ) ); } ); + + it( 'should load custom assertions automatically (Windows paths)', async () => { + const options = { + files: [ + 'basic-styles' + ], + production: true + }; + + vi.mocked( fs ).readdirSync.mockReturnValue( [ 'assertion-a.js', 'assertion-b.js' ] ); + + vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ + '\\workspace\\packages\\ckeditor5-basic-styles\\tests\\**\\*.js', + '\\workspace\\packages\\ckeditor-basic-styles\\tests\\**\\*.js' + ] ); + + vi.mocked( globSync ) + .mockReturnValue( [] ) + .mockReturnValueOnce( [ + '\\workspace\\packages\\ckeditor5-basic-styles\\tests\\bold.js', + '\\workspace\\packages\\ckeditor5-basic-styles\\tests\\italic.js' + ] ); + + const promise = runAutomatedTests( options ); + + setTimeout( () => { + expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); + + const [ firstCall ] = stubs.karma.server.constructor.mock.calls; + const [ , exitCallback ] = firstCall; + + exitCallback( 0 ); + } ); + + await promise; + + expect( vi.mocked( mkdirp ).sync ).toHaveBeenCalledExactlyOnceWith( '/workspace/build/.automated-tests' ); + expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( + '/workspace/build/.automated-tests/entry-point.js', + expect.stringContaining( [ + 'import "/workspace/packages/ckeditor5-basic-styles/tests/bold.js";', + 'import "/workspace/packages/ckeditor5-basic-styles/tests/italic.js";' + ].join( '\n' ) ) + ); + } ); } );