Array.reverse mutates in place — a defensive double-run() would have re-reversed the items. Iterate over a copy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
52 lines
1.4 KiB
TypeScript
52 lines
1.4 KiB
TypeScript
import type { APIRequestContext } from '@playwright/test';
|
|
import { adminApi } from './api';
|
|
|
|
// Resources to delete after a test, in LIFO order. Tests register
|
|
// their creations and the registry tears everything down in
|
|
// `cleanupRegistered` — typically called from `test.afterEach`.
|
|
|
|
type Cleanup = (api: APIRequestContext) => Promise<void>;
|
|
|
|
export class CleanupRegistry {
|
|
private items: Cleanup[] = [];
|
|
|
|
app(slugOrId: string): void {
|
|
this.items.push(async (api) => {
|
|
await api.delete(`/api/v1/admin/apps/${encodeURIComponent(slugOrId)}?force=true`);
|
|
});
|
|
}
|
|
|
|
adminUser(userId: string): void {
|
|
this.items.push(async (api) => {
|
|
await api.delete(`/api/v1/admin/admins/${userId}`);
|
|
});
|
|
}
|
|
|
|
apiKey(keyId: string): void {
|
|
this.items.push(async (api) => {
|
|
await api.delete(`/api/v1/admin/api-keys/${keyId}`);
|
|
});
|
|
}
|
|
|
|
async run(): Promise<void> {
|
|
if (this.items.length === 0) return;
|
|
const api = await adminApi();
|
|
try {
|
|
// Copy-then-reverse so a defensive double-`run()` (or a
|
|
// caller that inspects the registry after a partial
|
|
// teardown) doesn't see the items in a re-reversed order.
|
|
for (const item of [...this.items].reverse()) {
|
|
try {
|
|
await item(api);
|
|
} catch {
|
|
// Best-effort cleanup — a missing resource (already
|
|
// deleted by the test) shouldn't fail the suite.
|
|
}
|
|
}
|
|
} finally {
|
|
await api.dispose();
|
|
this.items = [];
|
|
}
|
|
}
|
|
}
|