* Make self-host tests CI-safe * Await cloud db teardown * Give local e2e boots more headroom * Keep main CI runs alive * Cache CI dependencies and image layers * Wait for recorded introspection requests in graphql plugin tests * Size self-host test budget for loaded runners * Probe test http servers for readiness before use * Die on recorder wait timeout instead of typing a string error * Type the recorder wait timeout as a tagged error * Update e2e locators for the integration copy renames * Keep stale data rendered while a refresh is waiting * Guard create-org input against hydration clobbering * Match the new sign-in heading in the selfhost callback test
Showing the changes to packages/plugins (2 of 27 files). Show all
Unified · Split
| @@ -32,6 +32,7 @@ import { · 31 unmodified lines | ||
| 32 | 32 | makeGreetingGraphqlSchema, |
| 33 | 33 | serveGraphqlFailureTestServer, |
| 34 | 34 | serveGraphqlTestServer, |
| 35 | + waitForRecordedRequests, | |
| 35 | 36 | } from "../testing"; |
| 36 | 37 | |
| 37 | 38 | // removed: v1 secret browser-handoff, credential-binding scopes, usagesForSecret/ |
| @@ -313,9 +314,8 @@ describe("graphqlPlugin real protocol server", () => { · 275 unmodified lines | ||
| 313 | 314 | value: "unused", |
| 314 | 315 | }); |
| 315 | 316 | |
| 316 | − const afterConnect = yield* server.requests; | |
| 317 | − expect(afterConnect.some((request) => request.payload.query?.includes("__schema"))).toBe( | |
| 318 | − true, | |
| 317 | + yield* waitForRecordedRequests(server.requests, (requests) => | |
| 318 | + requests.some((request) => request.payload.query?.includes("__schema")), | |
| 319 | 319 | ); |
| 320 | 320 | |
| 321 | 321 | const tools = yield* executor.tools.list(); |
| @@ -550,11 +550,12 @@ describe("graphqlPlugin real protocol server", () => { · 228 unmodified lines | ||
| 550 | 550 | value: "connect-token", |
| 551 | 551 | }); |
| 552 | 552 | |
| 553 | − const afterConnect = yield* server.requests; | |
| 553 | + const afterConnect = yield* waitForRecordedRequests(server.requests, (requests) => | |
| 554 | + requests.some((request) => request.payload.query?.includes("__schema")), | |
| 555 | + ); | |
| 554 | 556 | const introspectionRequests = afterConnect.filter((request) => |
| 555 | 557 | request.payload.query?.includes("__schema"), |
| 556 | 558 | ); |
| 557 | − expect(introspectionRequests.length).toBeGreaterThan(0); | |
| 558 | 559 | expect(introspectionRequests[0]?.headers.authorization).toBe("Bearer connect-token"); |
| 559 | 560 | |
| 560 | 561 | // The introspected operations become per-connection tools. |
| @@ -5,6 +5,7 @@ import { · 4 unmodified lines | ||
| 5 | 5 | Layer, |
| 6 | 6 | Predicate, |
| 7 | 7 | Ref, |
| 8 | + Schedule, | |
| 8 | 9 | Schema as EffectSchema, |
| 9 | 10 | Scope, |
| 10 | 11 | } from "effect"; |
| @@ -54,6 +55,28 @@ export interface GraphqlTestServerShape { · 43 unmodified lines | ||
| 54 | 55 | readonly clearRequests: Effect.Effect<void>; |
| 55 | 56 | } |
| 56 | 57 | |
| 58 | +export class GraphqlTestRecorderTimeoutError extends Data.TaggedError( | |
| 59 | + "GraphqlTestRecorderTimeoutError", | |
| 60 | +)<{ | |
| 61 | + readonly message: string; | |
| 62 | +}> {} | |
| 63 | + | |
| 64 | +/** Poll the request recorder until `predicate` matches. Yoga captures requests | |
| 65 | + * asynchronously (`captureRequest` runs via `Effect.runPromise` in the handler | |
| 66 | + * context), so connect/invoke can resolve before the ref updates under load. */ | |
| 67 | +export const waitForRecordedRequests = ( | |
| 68 | + requests: Effect.Effect<readonly GraphqlTestRequest[]>, | |
| 69 | + predicate: (requests: readonly GraphqlTestRequest[]) => boolean, | |
| 70 | + message = "timed out waiting for matching recorded GraphQL requests", | |
| 71 | +): Effect.Effect<readonly GraphqlTestRequest[], GraphqlTestRecorderTimeoutError> => | |
| 72 | + requests.pipe( | |
| 73 | + Effect.filterOrFail( | |
| 74 | + (all) => predicate(all), | |
| 75 | + () => new GraphqlTestRecorderTimeoutError({ message }), | |
| 76 | + ), | |
| 77 | + Effect.retry(Schedule.both(Schedule.spaced("50 millis"), Schedule.recurs(100))), | |
| 78 | + ); | |
| 79 | + | |
| 57 | 80 | class GraphqlTestServerAddressError extends Data.TaggedError("GraphqlTestServerAddressError")<{ |
| 58 | 81 | readonly address: unknown; |
| 59 | 82 | }> {} |