Skip to content

Commit 809ca8d

Browse files
authored
Merge branch 'dev' into cl/hexclave-pr1
2 parents 5ad6888 + 1044144 commit 809ca8d

2 files changed

Lines changed: 51 additions & 6 deletions

File tree

.claude/CLAUDE-KNOWLEDGE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,6 @@ A: Keep the real outbound SMTP policy in `apps/backend/src/private/implementatio
550550

551551
## Q: What project-level `sourceOfTruth` config is supported?
552552
A: Project config overrides only support the hosted `sourceOfTruth` shape. Legacy external source-of-truth overrides such as Postgres or Neon are removed by `migrateConfigOverride("project", ...)`, while raw schema validation should reject them.
553+
554+
## Q: How should managed email onboarding e2e tests wait for mock verification?
555+
A: Do not rely on a fixed `wait(1500)` after setup. The mock onboarding path flips the domain to `verified` asynchronously through `runAsynchronously`, so tests should poll the managed-onboarding check endpoint until the expected status appears.

apps/e2e/tests/backend/endpoints/api/v1/internal/managed-email-onboarding.test.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,34 @@ import { describe } from "vitest";
33
import { it } from "../../../../../helpers";
44
import { Project, niceBackendFetch } from "../../../../backend-helpers";
55

6+
async function waitForManagedDomainStatus(options: {
7+
domainId: string,
8+
subdomain: string,
9+
senderLocalPart: string,
10+
status: string,
11+
}) {
12+
const deadline = performance.now() + 10_000;
13+
let lastBody: unknown = undefined;
14+
while (performance.now() < deadline) {
15+
const response = await niceBackendFetch("/api/v1/internal/emails/managed-onboarding/check", {
16+
method: "POST",
17+
accessType: "admin",
18+
body: {
19+
domain_id: options.domainId,
20+
subdomain: options.subdomain,
21+
sender_local_part: options.senderLocalPart,
22+
},
23+
});
24+
lastBody = response.body;
25+
if (response.status === 200 && response.body.status === options.status) {
26+
return;
27+
}
28+
await wait(250);
29+
}
30+
31+
throw new Error(`Timed out waiting for managed email domain ${options.domainId} to become ${options.status}; last response body: ${JSON.stringify(lastBody)}`);
32+
}
33+
634
describe("managed email onboarding internal endpoints", () => {
735
it("rejects client access for setup endpoint", async ({ expect }) => {
836
await Project.createAndSwitch();
@@ -51,10 +79,14 @@ describe("managed email onboarding internal endpoints", () => {
5179
expect(setupResponse.body.domain_id).toBeDefined();
5280
expect(setupResponse.body.status).toBe("pending_verification");
5381

54-
// Mock onboarding asynchronously flips status to "verified" ~1s after setup
55-
// (mirroring the real Resend webhook flow). Wait for the transition before
56-
// asserting verified state.
57-
await wait(1500);
82+
// Mock onboarding asynchronously flips status to "verified" after setup,
83+
// mirroring the real Resend webhook flow.
84+
await waitForManagedDomainStatus({
85+
domainId: setupResponse.body.domain_id,
86+
subdomain: "mail.example.com",
87+
senderLocalPart: "noreply",
88+
status: "verified",
89+
});
5890

5991
const listResponse = await niceBackendFetch("/api/v1/internal/emails/managed-onboarding/list", {
6092
method: "GET",
@@ -202,7 +234,12 @@ describe("managed email onboarding internal endpoints", () => {
202234
sender_local_part: "noreply",
203235
},
204236
});
205-
await wait(1500);
237+
await waitForManagedDomainStatus({
238+
domainId: setupResponse.body.domain_id,
239+
subdomain: "mail.example.com",
240+
senderLocalPart: "noreply",
241+
status: "verified",
242+
});
206243

207244
const applyResponse = await niceBackendFetch("/api/v1/internal/emails/managed-onboarding/apply", {
208245
method: "POST",
@@ -240,7 +277,12 @@ describe("managed email onboarding internal endpoints", () => {
240277
sender_local_part: "noreply",
241278
},
242279
});
243-
await wait(1500);
280+
await waitForManagedDomainStatus({
281+
domainId: setupResponse.body.domain_id,
282+
subdomain: "mail.example.com",
283+
senderLocalPart: "noreply",
284+
status: "verified",
285+
});
244286

245287
const applyResponse = await niceBackendFetch("/api/v1/internal/emails/managed-onboarding/apply", {
246288
method: "POST",

0 commit comments

Comments
 (0)