diff --git a/packages/playwright-core/src/utils/fileUtils.ts b/packages/playwright-core/src/utils/fileUtils.ts index 6a67649a25..b624172923 100644 --- a/packages/playwright-core/src/utils/fileUtils.ts +++ b/packages/playwright-core/src/utils/fileUtils.ts @@ -15,8 +15,10 @@ */ import fs from 'fs'; +import type { WriteFileOptions } from 'fs'; import path from 'path'; import { rimraf } from '../utilsBundle'; +import { createGuid } from './crypto'; export const existsAsync = (path: string): Promise => new Promise(resolve => fs.stat(path, err => resolve(!err))); @@ -53,3 +55,11 @@ export async function copyFileAndMakeWritable(from: string, to: string) { export function sanitizeForFilePath(s: string) { return s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-'); } + +export function writeFileSyncAtomic(aPath: string, data: Buffer | string, options: WriteFileOptions) { + const dirName = path.dirname(aPath); + const fileName = path.basename(aPath); + const tmpPath = path.join(dirName, fileName + '-' + createGuid()); + fs.writeFileSync(tmpPath, data, options); + fs.renameSync(tmpPath, aPath); +} diff --git a/packages/playwright-test/src/transform/compilationCache.ts b/packages/playwright-test/src/transform/compilationCache.ts index 7c2fff7f3b..f4d8c9d6e8 100644 --- a/packages/playwright-test/src/transform/compilationCache.ts +++ b/packages/playwright-test/src/transform/compilationCache.ts @@ -18,6 +18,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import { sourceMapSupport } from '../utilsBundle'; +import { writeFileSyncAtomic } from 'playwright-core/lib/utils'; export type MemoryCache = { codePath: string; @@ -85,8 +86,8 @@ export function getFromCompilationCache(filename: string, hash: string, moduleUr addToCache: (code: string, map: any) => { fs.mkdirSync(path.dirname(cachePath), { recursive: true }); if (map) - fs.writeFileSync(sourceMapPath, JSON.stringify(map), 'utf8'); - fs.writeFileSync(codePath, code, 'utf8'); + writeFileSyncAtomic(sourceMapPath, JSON.stringify(map), 'utf8'); + writeFileSyncAtomic(codePath, code, 'utf8'); _innerAddToCompilationCache(filename, { codePath, sourceMapPath, moduleUrl }); } }; diff --git a/packages/playwright-test/src/transform/transform.ts b/packages/playwright-test/src/transform/transform.ts index 9b29991660..f5530a6604 100644 --- a/packages/playwright-test/src/transform/transform.ts +++ b/packages/playwright-test/src/transform/transform.ts @@ -166,7 +166,7 @@ export function transformHook(originalCode: string, filename: string, moduleUrl? const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM!]] as BabelPlugin[] : []; const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue); const { cachedCode, addToCache } = getFromCompilationCache(filename, hash, moduleUrl); - if (cachedCode) + if (cachedCode !== undefined) return cachedCode; // We don't use any browserslist data, but babel checks it anyway.