Unified · Split
| @@ -327,6 +327,14 @@ for (const origin of ["integration", "workspace"] as const) { · 326 unmodified lines | |||
| 327 | }); | 327 | }); |
| 328 | yield* Effect.addFinalizer(() => | 328 | yield* Effect.addFinalizer(() => |
| 329 | Effect.gen(function* () { | 329 | Effect.gen(function* () { |
| 330 | const connections = yield* client.connections.list({ query: { integration: slug } }); | ||
| 331 | for (const connection of connections) { | ||
| 332 | yield* client.connections | ||
| 333 | .remove({ | ||
| 334 | params: { owner: connection.owner, integration: slug, name: connection.name }, | ||
| 335 | }) | ||
| 336 | .pipe(Effect.ignore); | ||
| 337 | } | ||
| 330 | yield* client.mcp.removeServer({ params: { slug } }).pipe(Effect.ignore); | 338 | yield* client.mcp.removeServer({ params: { slug } }).pipe(Effect.ignore); |
| 331 | yield* client.oauth | 339 | yield* client.oauth |
| 332 | .removeClient({ params: { slug: app }, payload: { owner: "org" } }) | 340 | .removeClient({ params: { slug: app }, payload: { owner: "org" } }) |
| @@ -355,17 +363,13 @@ for (const origin of ["integration", "workspace"] as const) { · 22 unmodified lines | |||
| 355 | ...(origin === "integration" ? { originIntegration: slug } : {}), | 363 | ...(origin === "integration" ? { originIntegration: slug } : {}), |
| 356 | }, | 364 | }, |
| 357 | }); | 365 | }); |
| 358 | const savedClients = yield* client.oauth.listClients({}); | ||
| 359 | expect(savedClients.find((saved) => saved.slug === app)?.origin).toEqual( | ||
| 360 | origin === "integration" | ||
| 361 | ? { kind: "manual", integration: slug } | ||
| 362 | : { kind: "manual", integration: null }, | ||
| 363 | ); | ||
| 364 | yield* Effect.promise(() => emulator.ledger.clear()); | 366 | yield* Effect.promise(() => emulator.ledger.clear()); |
| 365 | yield* browser.session(identity, async ({ page, step }) => { | 367 | yield* browser.session(identity, async ({ page, step }) => { |
| 366 | await step("Open an integration that already has a saved OAuth app", async () => { | 368 | await step("Open an integration that already has a saved OAuth app", async () => { |
| 367 | await visit(page, `/integrations/${slug}?addAccount=1`); | 369 | await visit(page, `/integrations/${slug}?addAccount=1`); |
| 368 | await page.getByRole("tab", { name: "OAuth", exact: true }).waitFor(); | 370 | await page.getByRole("tab", { name: "OAuth", exact: true }).waitFor(); |
| 371 | }); | ||
| 372 | await step("Connect once using the saved app", async () => { | ||
| 369 | const opened = page.waitForEvent("popup"); | 373 | const opened = page.waitForEvent("popup"); |
| 370 | await page.getByRole("button", { name: /^Connect(?: with OAuth)?$/ }).click(); | 374 | await page.getByRole("button", { name: /^Connect(?: with OAuth)?$/ }).click(); |
| 371 | const popup = await opened; | 375 | const popup = await opened; |
| @@ -374,14 +378,28 @@ for (const origin of ["integration", "workspace"] as const) { · 2 unmodified lines | |||
| 374 | new URL(popup.url()).searchParams.get("client_id"), | 378 | new URL(popup.url()).searchParams.get("client_id"), |
| 375 | "the existing app is reused without another registration step", | 379 | "the existing app is reused without another registration step", |
| 376 | ).toBe(registered.client_id); | 380 | ).toBe(registered.client_id); |
| 377 | await popup.close(); | 381 | }); |
| 382 | await step("Approve provider sign-in and save the connection", async () => { | ||
| 383 | const popup = page | ||
| 384 | .context() | ||
| 385 | .pages() | ||
| 386 | .find((candidate) => candidate !== page); | ||
| 387 | if (!popup) throw new Error("Provider sign-in window was not open"); | ||
| 388 | await popup.getByRole("button", { name: /admin/ }).click(); | ||
| 378 | await page | 389 | await page |
| 379 | .getByRole("dialog") | 390 | .getByRole("heading", { name: /Add connection/ }) |
| 380 | .getByRole("button", { name: "Close", exact: true }) | 391 | .waitFor({ state: "hidden", timeout: 30_000 }); |
| 381 | .last() | ||
| 382 | .click(); | ||
| 383 | }); | 392 | }); |
| 384 | }); | 393 | }); |
| 394 | const connections = yield* client.connections.list({ query: { integration: slug } }); | ||
| 395 | expect(connections, "provider consent saves the connection").toHaveLength(1); | ||
| 396 | expect(connections[0]?.owner, "a shared app keeps the connection personal").toBe("user"); | ||
| 397 | const savedClients = yield* client.oauth.listClients({}); | ||
| 398 | expect(savedClients.find((saved) => saved.slug === app)?.origin).toEqual( | ||
| 399 | origin === "integration" | ||
| 400 | ? { kind: "manual", integration: slug } | ||
| 401 | : { kind: "manual", integration: null }, | ||
| 402 | ); | ||
| 385 | const ledger = yield* Effect.promise(() => emulator.ledger.list()); | 403 | const ledger = yield* Effect.promise(() => emulator.ledger.list()); |
| 386 | expect( | 404 | expect( |
| 387 | ledger.filter((entry) => entry.method === "POST" && entry.path === "/register"), | 405 | ledger.filter((entry) => entry.method === "POST" && entry.path === "/register"), |