Isolate the comments e2e pack in its own pond (#92)
Some checks failed
CD / Build and push images (push) Successful in 1m5s
CD / Deploy to Test (push) Successful in 10s
CD / Smoke tests against Test (push) Successful in 1m10s
CD / Promote to Int (push) Successful in 10s
CI / Lint, typecheck, test (push) Successful in 3m17s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Failing after 2m45s
CI / Import/export fidelity gate (push) Has been skipped
Some checks failed
CD / Build and push images (push) Successful in 1m5s
CD / Deploy to Test (push) Successful in 10s
CD / Smoke tests against Test (push) Successful in 1m10s
CD / Promote to Int (push) Successful in 10s
CI / Lint, typecheck, test (push) Successful in 3m17s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Failing after 2m45s
CI / Import/export fidelity gate (push) Has been skipped
The shared fixture pond accumulates grants from earlier packs in the same CI job, so "fixture-editor is only a reader" did not hold there and the policy test failed in CI while passing locally. A Site Admin now lifts fixture-user's additional-pond quota for the run, the pack provisions a fresh pond and page, and tears both down afterwards; the policy PATCH is also asserted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
This commit is contained in:
parent
e54aaf76f9
commit
c7d3b20ca0
@ -1,4 +1,4 @@
|
||||
import { expect, test, type BrowserContext } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { contextForUser } from './helpers';
|
||||
|
||||
@ -13,54 +13,56 @@ const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:5173';
|
||||
|
||||
let pondId: string;
|
||||
let pageUrl: string;
|
||||
let pageId: string;
|
||||
let readerUserId: string;
|
||||
|
||||
async function pondOf(owner: BrowserContext): Promise<{ id: string; slug: string }> {
|
||||
const ponds = (await (await owner.request.get('/api/v1/ponds')).json()) as {
|
||||
id: string;
|
||||
slug: string;
|
||||
type: string;
|
||||
}[];
|
||||
const shared = ponds.find((p) => p.type === 'shared');
|
||||
expect(shared).toBeTruthy();
|
||||
return shared!;
|
||||
}
|
||||
let ownerId: string;
|
||||
|
||||
// The pack provisions its OWN pond: the shared fixture pond accumulates
|
||||
// grants from earlier packs in the same CI job (access-rules & friends), so
|
||||
// "fixture-editor is only a reader here" would not hold there. A Site Admin
|
||||
// lifts fixture-user's additional-pond quota for the run.
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
const admin = await contextForUser(browser, BASE_URL, 'fixture-admin');
|
||||
const lookup = (await (await admin.request.get('/api/v1/admin/users?q=fixture-user')).json()) as {
|
||||
users: { id: string; username: string }[];
|
||||
};
|
||||
ownerId = lookup.users.find((u) => u.username === 'fixture-user')!.id;
|
||||
const quota = await admin.request.put(`/api/v1/admin/quotas/user/${ownerId}/additional_ponds`, {
|
||||
data: { value: 10 },
|
||||
});
|
||||
expect(quota.ok()).toBe(true);
|
||||
await admin.close();
|
||||
|
||||
const owner = await contextForUser(browser, BASE_URL, 'fixture-user');
|
||||
const pond = await pondOf(owner);
|
||||
const pondRes = await owner.request.post('/api/v1/ponds', {
|
||||
data: { name: `Comments stage ${Date.now()}` },
|
||||
});
|
||||
expect(pondRes.ok()).toBe(true);
|
||||
const pond = (await pondRes.json()) as { id: string; slug: string };
|
||||
pondId = pond.id;
|
||||
|
||||
// Fresh page per run — never depends on fixture pages' trash state.
|
||||
const created = await owner.request.post(`/api/v1/ponds/${pondId}/pages`, {
|
||||
data: { title: `Comment stage ${Date.now()}` },
|
||||
data: { title: 'Discussion' },
|
||||
});
|
||||
expect(created.ok()).toBe(true);
|
||||
const page = (await created.json()) as { id: string; slug: string };
|
||||
pageId = page.id;
|
||||
const page = (await created.json()) as { slug: string };
|
||||
pageUrl = `/p/${pond.slug}/${page.slug}`;
|
||||
|
||||
// fixture-editor becomes a reader-member of the pond (the second user);
|
||||
// a leftover membership from an aborted run just yields a conflict we ignore.
|
||||
await owner.request.post(`/api/v1/ponds/${pondId}/members`, {
|
||||
// fixture-editor is exactly a reader in this fresh pond — nothing else.
|
||||
const member = await owner.request.post(`/api/v1/ponds/${pondId}/members`, {
|
||||
data: { usernameOrEmail: 'fixture-editor', role: 'reader' },
|
||||
});
|
||||
const members = (await (await owner.request.get(`/api/v1/ponds/${pondId}/members`)).json()) as {
|
||||
members: { id: string; username: string }[];
|
||||
};
|
||||
readerUserId = members.members.find((m) => m.username === 'fixture-editor')!.id;
|
||||
// Deterministic starting policy.
|
||||
await owner.request.patch(`/api/v1/ponds/${pondId}`, { data: { commentPolicy: 'readers' } });
|
||||
expect(member.ok()).toBe(true);
|
||||
await owner.close();
|
||||
});
|
||||
|
||||
test.afterAll(async ({ browser }) => {
|
||||
const owner = await contextForUser(browser, BASE_URL, 'fixture-user');
|
||||
await owner.request.patch(`/api/v1/ponds/${pondId}`, { data: { commentPolicy: 'readers' } });
|
||||
if (readerUserId) await owner.request.delete(`/api/v1/ponds/${pondId}/members/${readerUserId}`);
|
||||
if (pageId) await owner.request.delete(`/api/v1/pages/${pageId}`);
|
||||
if (pondId) await owner.request.delete(`/api/v1/ponds/${pondId}`);
|
||||
await owner.close();
|
||||
const admin = await contextForUser(browser, BASE_URL, 'fixture-admin');
|
||||
if (ownerId) {
|
||||
await admin.request.delete(`/api/v1/admin/quotas/user/${ownerId}/additional_ponds`);
|
||||
}
|
||||
await admin.close();
|
||||
});
|
||||
|
||||
test('two users run the full comment lifecycle with resolve/unresolve', async ({ browser }) => {
|
||||
@ -130,7 +132,10 @@ test('two users run the full comment lifecycle with resolve/unresolve', async ({
|
||||
|
||||
test('the composer hides with a hint when the policy bars readers', async ({ browser }) => {
|
||||
const owner = await contextForUser(browser, BASE_URL, 'fixture-user');
|
||||
await owner.request.patch(`/api/v1/ponds/${pondId}`, { data: { commentPolicy: 'editors' } });
|
||||
const patched = await owner.request.patch(`/api/v1/ponds/${pondId}`, {
|
||||
data: { commentPolicy: 'editors' },
|
||||
});
|
||||
expect(patched.ok()).toBe(true);
|
||||
await owner.close();
|
||||
|
||||
const reader = await contextForUser(browser, BASE_URL, 'fixture-editor');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user