// Selfhost-only (browser): the connect modal's API-key credential UX.// - the credential field MERGES the placement's lead + prefix as an affix, so// it reads as the header value being built ("Authorization: Bearer ▏token");// - the "Add authentication method" editor offers placement presets;// - a prefix with no trailing space (sent joined to the value) warns, and the// warning clears once the space is restored;// - a very long pasted key wraps inside the dialog instead of stretching it// past the viewport (the preview breaks mid-token, the merged affix// truncates).// Video is the artifact.import { randomBytes } from "node:crypto"; import { expect } from "@effect/vitest";import { Effect } from "effect";import { composePluginApi } from "@executor-js/api/server";import { openApiHttpPlugin } from "@executor-js/plugin-openapi/api";import { IntegrationSlug } from "@executor-js/sdk/shared"; import { scenario } from "../src/scenario";import { Api, Browser, Target } from "../src/services"; const api = composePluginApi([openApiHttpPlugin()] as const); /** Horizontal overflow of the open dialog in px (0 = fits). Infinity when no * dialog is open, so an assertion against it always fails loudly. */const dialogOverflow = (page: { readonly evaluate: <T>(fn: () => T) => Promise<T>;}): Promise<number> => page.evaluate(() => { const dialog = document.querySelector('[role="dialog"]'); return dialog === null ? Number.POSITIVE_INFINITY : dialog.scrollWidth - dialog.clientWidth; }); const bearerSpec = (): string => JSON.stringify({ openapi: "3.0.3", info: { title: "Bearer Fixture", version: "1.0.0" }, servers: [{ url: "https://api.bearerfix.test" }], security: [{ bearerAuth: [] }], components: { securitySchemes: { bearerAuth: { type: "http", scheme: "bearer" } } }, paths: { "/ping": { get: { operationId: "ping", responses: { "200": { description: "ok" } } } }, }, }); scenario( "Connect modal · API key credential UX: merged affix, add-method, prefix warning", {}, Effect.scoped( Effect.gen(function* () { const target = yield* Target; const { client: makeApiClient } = yield* Api; const browser = yield* Browser; const identity = yield* target.newIdentity(); const apiClient = yield* makeApiClient(api, identity); const slug = `connect_ux_${randomBytes(4).toString("hex")}`; yield* Effect.ensuring( Effect.gen(function* () { yield* apiClient.openapi.addSpec({ payload: { spec: { kind: "blob", value: bearerSpec() }, slug }, }); yield* browser.session(identity, async ({ page, step }) => { await step("Open the connect modal", async () => { await page.goto(`/integrations/${slug}?addAccount=1`, { waitUntil: "networkidle" }); await page.getByRole("heading", { name: /Add connection/ }).waitFor(); }); await step("The credential field merges the placement prefix", async () => { // The placement's lead + prefix renders as a non-editable affix // inside the field, so there is no separate preview line. await page.getByText("Authorization: Bearer").first().waitFor(); }); await step("The add-method editor offers placement presets", async () => { await page.getByRole("button", { name: "Add authentication method" }).click(); await page.getByRole("heading", { name: "Add authentication method" }).waitFor(); await page.getByRole("button", { name: "Bearer header" }).waitFor(); await page.getByRole("button", { name: "API key query" }).waitFor(); }); await step("A prefix with no trailing space warns", async () => { await page.getByPlaceholder("Bearer ").first().fill("Bearer"); await page.getByText("Prefix has no trailing space").waitFor(); }); await step("Restoring the trailing space clears the warning", async () => { await page.getByPlaceholder("Bearer ").first().fill("Bearer "); await page.getByText("Prefix has no trailing space").waitFor({ state: "detached" }); }); await step("A long pasted key never widens the dialog", async () => { // A key mistakenly pasted into Prefix is the worst case: one // unbroken 700-char token rendered into the preview line. The // dialog must keep its width (the preview wraps mid-token). const longKey = `${"x".repeat(300)}Bearer${"x".repeat(400)}`; // The preview line renders only once the placement is named. await page.getByPlaceholder("Authorization").first().fill("Authorization"); await page.getByPlaceholder("Bearer ").first().fill(longKey); await page.getByText("Preview").waitFor(); // ≤ 1px: subpixel rounding can report a fractional scrollWidth. expect( await dialogOverflow(page), "the add-method dialog must not scroll horizontally", ).toBeLessThanOrEqual(1); }); await step("The merged affix truncates a long saved prefix", async () => { // Saving the method returns to the connect modal with the new // method selected; its credential field merges the (700-char) // prefix as the affix, which must truncate inside the field. await page.getByRole("button", { name: "Add method", exact: true }).click(); await page.getByRole("heading", { name: /Add connection/ }).waitFor(); await page.getByText("Authorization: x").first().waitFor(); expect( await dialogOverflow(page), "the connect modal must not scroll horizontally", ).toBeLessThanOrEqual(1); }); }); }), apiClient.openapi .removeSpec({ params: { slug: IntegrationSlug.make(slug) } }) .pipe(Effect.ignore), ); }), ),);
// Selfhost-only (browser): the connect modal's API-key credential UX.
// - the credential field MERGES the placement's lead + prefix as an affix, so
// it reads as the header value being built ("Authorization: Bearer ▏token");
// - the "Add authentication method" editor offers placement presets;
// - a prefix with no trailing space (sent joined to the value) warns, and the
// warning clears once the space is restored;
// - a very long pasted key wraps inside the dialog instead of stretching it
// past the viewport (the preview breaks mid-token, the merged affix
// truncates).
// Video is the artifact.
import { randomBytes } from "node:crypto";
import { expect } from "@effect/vitest";
import { Effect } from "effect";
import { composePluginApi } from "@executor-js/api/server";
import { openApiHttpPlugin } from "@executor-js/plugin-openapi/api";
import { IntegrationSlug } from "@executor-js/sdk/shared";
import { scenario } from "../src/scenario";
import { Api, Browser, Target } from "../src/services";
const api = composePluginApi([openApiHttpPlugin()] as const);
/** Horizontal overflow of the open dialog in px (0 = fits). Infinity when no
* dialog is open, so an assertion against it always fails loudly. */
const dialogOverflow = (page: {
readonly evaluate: <T>(fn: () => T) => Promise<T>;
}): Promise<number> =>
page.evaluate(() => {
const dialog = document.querySelector('[role="dialog"]');
return dialog === null ? Number.POSITIVE_INFINITY : dialog.scrollWidth - dialog.clientWidth;
});
const bearerSpec = (): string =>
JSON.stringify({
openapi: "3.0.3",
info: { title: "Bearer Fixture", version: "1.0.0" },
servers: [{ url: "https://api.bearerfix.test" }],
security: [{ bearerAuth: [] }],
components: { securitySchemes: { bearerAuth: { type: "http", scheme: "bearer" } } },
paths: {
"/ping": { get: { operationId: "ping", responses: { "200": { description: "ok" } } } },
},
});
scenario(
"Connect modal · API key credential UX: merged affix, add-method, prefix warning",
{},
Effect.scoped(
Effect.gen(function* () {
const target = yield* Target;
const { client: makeApiClient } = yield* Api;
const browser = yield* Browser;
const identity = yield* target.newIdentity();
const apiClient = yield* makeApiClient(api, identity);
const slug = `connect_ux_${randomBytes(4).toString("hex")}`;
yield* Effect.ensuring(
Effect.gen(function* () {
yield* apiClient.openapi.addSpec({
payload: { spec: { kind: "blob", value: bearerSpec() }, slug },
});
yield* browser.session(identity, async ({ page, step }) => {
await step("Open the connect modal", async () => {
await page.goto(`/integrations/${slug}?addAccount=1`, { waitUntil: "networkidle" });
await page.getByRole("heading", { name: /Add connection/ }).waitFor();
});
await step("The credential field merges the placement prefix", async () => {
// The placement's lead + prefix renders as a non-editable affix
// inside the field, so there is no separate preview line.
await page.getByText("Authorization: Bearer").first().waitFor();
});
await step("The add-method editor offers placement presets", async () => {
await page.getByRole("button", { name: "Add authentication method" }).click();
await page.getByRole("heading", { name: "Add authentication method" }).waitFor();
await page.getByRole("button", { name: "Bearer header" }).waitFor();
await page.getByRole("button", { name: "API key query" }).waitFor();
});
await step("A prefix with no trailing space warns", async () => {
await page.getByPlaceholder("Bearer ").first().fill("Bearer");
await page.getByText("Prefix has no trailing space").waitFor();
});
await step("Restoring the trailing space clears the warning", async () => {
await page.getByPlaceholder("Bearer ").first().fill("Bearer ");
await page.getByText("Prefix has no trailing space").waitFor({ state: "detached" });
});
await step("A long pasted key never widens the dialog", async () => {
// A key mistakenly pasted into Prefix is the worst case: one
// unbroken 700-char token rendered into the preview line. The
// dialog must keep its width (the preview wraps mid-token).
const longKey = `${"x".repeat(300)}Bearer${"x".repeat(400)}`;
// The preview line renders only once the placement is named.
await page.getByPlaceholder("Authorization").first().fill("Authorization");
await page.getByPlaceholder("Bearer ").first().fill(longKey);
await page.getByText("Preview").waitFor();
// ≤ 1px: subpixel rounding can report a fractional scrollWidth.
expect(
await dialogOverflow(page),
"the add-method dialog must not scroll horizontally",
).toBeLessThanOrEqual(1);
});
await step("The merged affix truncates a long saved prefix", async () => {
// Saving the method returns to the connect modal with the new
// method selected; its credential field merges the (700-char)
// prefix as the affix, which must truncate inside the field.
await page.getByRole("button", { name: "Add method", exact: true }).click();
await page.getByRole("heading", { name: /Add connection/ }).waitFor();
await page.getByText("Authorization: x").first().waitFor();
expect(
await dialogOverflow(page),
"the connect modal must not scroll horizontally",
).toBeLessThanOrEqual(1);
});
});
}),
apiClient.openapi
.removeSpec({ params: { slug: IntegrationSlug.make(slug) } })
.pipe(Effect.ignore),
);
}),
),
);