如何将fixtures生成的测试数据ID传递至global.teardown.ts?
问题
我在fixtures.ts中调用API在数据库创建对象并获取其ID,希望所有测试完成后清理这些数据库对象。请问如何将这些ID传递至global.teardown.ts?
当前尝试方案
我尝试在global.teardown.ts中导入包含单例GUID数组的fixtures模块,但模块会被重新初始化,导致数组始终为空。
global.teardown.ts
import { entityGuidsToDelete, api } from './fixtures' async function globalTeardown() { // 无法正常工作,因为数组始终为空 for(const entityGuid of entityGuidsToDelete) { await api.deleteEntity(entityGuid); } } export default globalTeardown;
playwright.config.ts
export default defineConfig({ ... /* 为主流浏览器配置测试项目 */ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, ], globalTeardown: require.resolve('./global-teardown') });
fixtures.ts
type Fixtures = { userApi: Api; newEntity: LegalEntityModel; }; export const entityGuidsToDelete = new Array<string>(); export const test = base.extend<Fixtures>({ ... newEntity: async ({ userApi }, use) => { const newEntity = await createNewEntity() entityGuidsToDelete.push(newEntity.id); // 这段代码确实会被执行 await use(newEntity); } } export { expect } from '@playwright/test';
解决方法
Playwright的全局前置/后置钩子和测试fixtures运行在不同进程中,内存中的数组无法跨进程共享,推荐以下几种可行方案:
方案1:临时文件存储ID
在fixtures中将需要清理的ID写入临时JSON文件,全局后置钩子从文件读取ID并执行清理:
- 修改
fixtures.ts添加文件写入逻辑:
import fs from 'fs/promises'; import path from 'path'; const tempFile = path.join(__dirname, '.temp-entities.json'); // 初始化空文件,避免读取时出错 (async () => { await fs.writeFile(tempFile, JSON.stringify([]), 'utf-8'); })(); type Fixtures = { userApi: Api; newEntity: LegalEntityModel; }; export const test = base.extend<Fixtures>({ ... newEntity: async ({ userApi }, use) => { const newEntity = await createNewEntity(); // 读取现有ID并追加新ID const existingIds = JSON.parse(await fs.readFile(tempFile, 'utf-8')); existingIds.push(newEntity.id); await fs.writeFile(tempFile, JSON.stringify(existingIds), 'utf-8'); await use(newEntity); } } export { expect } from '@playwright/test';
- 修改
global.teardown.ts读取文件并清理:
import fs from 'fs/promises'; import path from 'path'; import { api } from './fixtures'; const tempFile = path.join(__dirname, '.temp-entities.json'); async function globalTeardown() { try { const entityGuids = JSON.parse(await fs.readFile(tempFile, 'utf-8')); for(const entityGuid of entityGuids) { await api.deleteEntity(entityGuid); } // 清理临时文件 await fs.unlink(tempFile); } catch (err) { console.error('清理资源失败:', err); } } export default globalTeardown;
方案2:测试结束后即时清理
如果不需要等待所有测试完成再统一清理,可以在fixture中添加后置清理逻辑,每个测试结束后立即删除对象:
newEntity: async ({ userApi }, use) => { const newEntity = await createNewEntity(); await use(newEntity); // 测试执行完成后立即清理当前对象 await userApi.deleteEntity(newEntity.id); }
这种方式无需依赖全局后置钩子,能避免测试间的资源依赖问题,适合独立测试场景。
方案3:使用环境变量传递(适合少量ID)
如果需要清理的ID数量不多,可以在fixtures中将ID拼接为字符串存入环境变量,全局后置钩子再解析该变量:
// fixtures.ts中添加 process.env.ENTITY_IDS = (process.env.ENTITY_IDS || '') + ',' + newEntity.id; // global.teardown.ts中解析 const entityGuids = (process.env.ENTITY_IDS || '').split(',').filter(Boolean);
内容的提问来源于stack exchange,提问作者Liero
相关产品推荐
相关产品推荐

