Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/utils/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,9 @@ const __dirname = __dirname_fn(__filename);
)

// Write the transpiled file with updated imports
const tempFile = filePath.replace(/\.ts$/, '.temp.mjs')
// Include process.pid + a random suffix so concurrent run-multiple workers
// don't write to and delete each other's temp files (see issue #5642).
const tempFile = filePath.replace(/\.ts$/, `.${process.pid}.${Math.random().toString(36).slice(2, 10)}.temp.mjs`)
fs.writeFileSync(tempFile, jsContent)
transpiledFiles.set(filePath, tempFile)
}
Expand Down
36 changes: 36 additions & 0 deletions test/unit/utils/typescript_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { expect } from 'chai'
import { fileURLToPath } from 'url'
import path from 'path'
import { createRequire } from 'module'
import { transpileTypeScript, cleanupTempFiles } from '../../../lib/utils/typescript.js'

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const require = createRequire(import.meta.url)
const typescript = require('typescript')

const configPath = path.resolve(__dirname, '../../data/typescript-config-imports/tests/api/codecept.conf.ts')

describe('TypeScript transpilation', () => {
it('uses unique temp file names per invocation so concurrent run-multiple workers do not delete each other (#5642)', async () => {
const first = await transpileTypeScript(configPath, typescript)
const second = await transpileTypeScript(configPath, typescript)

try {
expect(first.allTempFiles.length).to.be.greaterThan(0)
expect(second.allTempFiles.length).to.equal(first.allTempFiles.length)

// Every temp file path is still recognisable as a transpiled file
for (const file of [...first.allTempFiles, ...second.allTempFiles]) {
expect(file).to.match(/\.temp\.mjs$/)
}

// The two invocations must not share any temp file path, otherwise one
// worker's cleanup would remove files the other still needs to import.
const shared = first.allTempFiles.filter(f => second.allTempFiles.includes(f))
expect(shared, `temp files were shared between invocations: ${shared}`).to.be.empty
} finally {
cleanupTempFiles(first.allTempFiles)
cleanupTempFiles(second.allTempFiles)
}
})
})
Loading