Skip to content

Commit 94363d8

Browse files
tylerslatonclaude
andcommitted
fix(showcase/harness): probes accept BOTH idiomatic and legacy demo shapes
The harness D5 probes run against ALL 18 integrations, but only langgraph-python has the recent idiomatic refactors. Production PB showed 16 integrations green on chat-css and chat-slots, and 3 green on auth — shipping the previous pure-HALCYON / pure-SlotMarker / pure-SignInCard probes would have regressed those green cells to red. Made all three probes accept either shape, detected at runtime: - d5-chat-css: tries HALCYON anchors (ember border + JetBrains Mono + Fraunces) first, falls back to legacy hot-pink/amber background anchors. Either passing satisfies the assertion. Combined error message names both paths so operators can see WHICH theme the integration was supposed to match against. - d5-chat-slots: combined CSS-OR selector `[data-slot-label="MessageView.AssistantMessage"], [data-testid="custom-assistant-message"]`. Either marker on the page is sufficient evidence the slot wiring fired. - d5-auth: preFill detects shape via brief SignInCard probe — present → idiomatic (click sign-in to mount chat); absent → legacy (chat already mounted, no preFill action). Assertion clicks sign-out then races SignInCard re-mount (idiomatic pass) against banner-flip + error-surface (legacy pass). Each path has a discrete error message so operators can tell which contract failed. Tests rewritten to exercise both paths for each probe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent deb0b73 commit 94363d8

6 files changed

Lines changed: 474 additions & 169 deletions

File tree

showcase/harness/src/probes/scripts/d5-auth.test.ts

Lines changed: 103 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,38 @@ import {
99
SIGN_IN_BUTTON_SELECTOR,
1010
SIGN_IN_CARD_SELECTOR,
1111
SIGN_OUT_BUTTON_SELECTOR,
12+
AUTH_BANNER_UNAUTHENTICATED_SELECTOR,
13+
ERROR_BANNER_SELECTOR,
14+
ERROR_BOUNDARY_SELECTOR,
1215
} from "./d5-auth.js";
1316

1417
interface FakeOpts {
15-
/** Whether the sign-in button is initially visible. Default true. */
18+
/** Whether the SignInCard's sign-in button is visible at preFill time
19+
* (idiomatic shape detection). Default true (langgraph-python). */
1620
signInButtonVisible?: boolean;
17-
/** Whether the chat textarea mounts after sign-in. Default true. */
21+
/** Whether the chat textarea mounts after sign-in click. Default true. */
1822
textareaMountsAfterSignIn?: boolean;
1923
/** Whether the sign-out button is visible after authentication. Default true. */
2024
signOutButtonVisible?: boolean;
21-
/** Whether the SignInCard re-mounts after sign-out. Default true. */
25+
/** Whether the SignInCard re-mounts after sign-out (idiomatic-shape pass). */
2226
signInCardRemounts?: boolean;
27+
/** Whether the legacy banner flips to unauthenticated after sign-out. */
28+
legacyBannerFlipsToUnauth?: boolean;
29+
/** Whether the legacy error surface eventually appears. */
30+
legacyErrorSurfaceAppears?: boolean;
2331
}
2432

2533
function makePage(opts: FakeOpts): {
2634
page: Page;
2735
fakeClick: (p: Page, sel: string) => Promise<void>;
2836
} {
29-
let signedIn = false;
37+
let signedIn = !opts.signInButtonVisible; // legacy starts already-signed-in
3038
let signedOut = false;
3139
const page: Page = {
3240
async waitForSelector(selector: string) {
3341
if (selector === SIGN_IN_BUTTON_SELECTOR) {
3442
if (!(opts.signInButtonVisible ?? true)) {
35-
throw new Error("waitForSelector timeout (sign-in button missing)");
43+
throw new Error("waitForSelector timeout (legacy shape — no sign-in button)");
3644
}
3745
return;
3846
}
@@ -67,11 +75,22 @@ function makePage(opts: FakeOpts): {
6775
}
6876
return;
6977
}
78+
if (selector === AUTH_BANNER_UNAUTHENTICATED_SELECTOR) {
79+
if (!signedOut || !(opts.legacyBannerFlipsToUnauth ?? false)) {
80+
throw new Error(
81+
"waitForSelector timeout (legacy banner never flipped)",
82+
);
83+
}
84+
return;
85+
}
7086
},
7187
async fill() {},
7288
async press() {},
7389
async evaluate() {
74-
return undefined as never;
90+
// probeErrorSurfaceVisible asks for `[data-testid="auth-demo-error"]`
91+
// OR `[data-testid="auth-demo-chat-boundary"]` — return true after
92+
// sign-out if the legacy error surface should appear.
93+
return (signedOut && (opts.legacyErrorSurfaceAppears ?? false)) as never;
7594
},
7695
};
7796
const fakeClick = async (_p: Page, sel: string): Promise<void> => {
@@ -108,61 +127,121 @@ describe("d5-auth script", () => {
108127
expect(SIGN_OUT_BUTTON_SELECTOR).toBe(
109128
'[data-testid="auth-sign-out-button"]',
110129
);
130+
expect(AUTH_BANNER_UNAUTHENTICATED_SELECTOR).toBe(
131+
'[data-testid="auth-banner"][data-authenticated="false"]',
132+
);
133+
expect(ERROR_BANNER_SELECTOR).toBe('[data-testid="auth-demo-error"]');
134+
expect(ERROR_BOUNDARY_SELECTOR).toBe(
135+
'[data-testid="auth-demo-chat-boundary"]',
136+
);
111137
});
112138

113139
describe("buildAuthPreFill", () => {
114-
it("fails when sign-in button is not visible (demo loaded into wrong state)", async () => {
115-
const { page, fakeClick } = makePage({ signInButtonVisible: false });
116-
const preFill = buildAuthPreFill({ click: fakeClick });
117-
await expect(preFill(page)).rejects.toThrow(
118-
/sign-in button.*not visible/,
119-
);
140+
it("on idiomatic shape: clicks sign-in then waits for chat textarea", async () => {
141+
const { page, fakeClick } = makePage({
142+
signInButtonVisible: true,
143+
textareaMountsAfterSignIn: true,
144+
});
145+
const preFill = buildAuthPreFill({ click: fakeClick, detectTimeoutMs: 50 });
146+
await expect(preFill(page)).resolves.toBeUndefined();
120147
});
121148

122-
it("fails when chat textarea does not mount after sign-in", async () => {
149+
it("on idiomatic shape: fails when chat textarea does not mount after sign-in", async () => {
123150
const { page, fakeClick } = makePage({
151+
signInButtonVisible: true,
124152
textareaMountsAfterSignIn: false,
125153
});
126-
const preFill = buildAuthPreFill({ click: fakeClick });
154+
const preFill = buildAuthPreFill({ click: fakeClick, detectTimeoutMs: 50 });
127155
await expect(preFill(page)).rejects.toThrow(
128156
/chat textarea did not mount/,
129157
);
130158
});
131159

132-
it("succeeds when sign-in mounts the chat surface", async () => {
133-
const { page, fakeClick } = makePage({});
134-
const preFill = buildAuthPreFill({ click: fakeClick });
160+
it("on legacy shape: returns immediately (no sign-in click needed)", async () => {
161+
// No sign-in button visible → legacy shape → preFill is a no-op.
162+
const { page, fakeClick } = makePage({ signInButtonVisible: false });
163+
const preFill = buildAuthPreFill({ click: fakeClick, detectTimeoutMs: 50 });
135164
await expect(preFill(page)).resolves.toBeUndefined();
136165
});
137166
});
138167

139168
describe("buildAuthAssertion", () => {
140-
it("fails when sign-out button is not visible (sign-in path didn't authenticate)", async () => {
169+
it("fails when sign-out button is not visible", async () => {
141170
const { page, fakeClick } = makePage({ signOutButtonVisible: false });
142171
const assertion = buildAuthAssertion({
143172
signOutTimeoutMs: 50,
173+
detectTimeoutMs: 50,
144174
click: fakeClick,
145175
});
146176
await expect(assertion(page)).rejects.toThrow(
147177
/sign-out button.*not visible/,
148178
);
149179
});
150180

151-
it("fails when SignInCard does not re-mount after sign-out (tree didn't unmount)", async () => {
152-
const { page, fakeClick } = makePage({ signInCardRemounts: false });
181+
it("on idiomatic shape: succeeds when SignInCard re-mounts after sign-out", async () => {
182+
const { page, fakeClick } = makePage({
183+
signInButtonVisible: true,
184+
signOutButtonVisible: true,
185+
signInCardRemounts: true,
186+
});
153187
const assertion = buildAuthAssertion({
154-
signOutTimeoutMs: 50,
188+
signOutTimeoutMs: 5_000,
189+
detectTimeoutMs: 50,
155190
click: fakeClick,
156191
});
157192
await expect(assertion(page)).rejects.toThrow(
158193
/SignInCard.*did not re-mount/,
159194
);
160195
});
161196

162-
it("succeeds when SignInCard re-mounts after clicking sign-out", async () => {
163-
const { page, fakeClick } = makePage({});
164-
const assertion = buildAuthAssertion({ click: fakeClick });
197+
it("on legacy shape: succeeds when banner flips and error surface appears", async () => {
198+
const { page, fakeClick } = makePage({
199+
signInButtonVisible: false, // legacy
200+
signOutButtonVisible: true,
201+
signInCardRemounts: false, // legacy doesn't have SignInCard
202+
legacyBannerFlipsToUnauth: true,
203+
legacyErrorSurfaceAppears: true,
204+
});
205+
const assertion = buildAuthAssertion({
206+
signOutTimeoutMs: 5_000,
207+
detectTimeoutMs: 50,
208+
click: fakeClick,
209+
});
165210
await expect(assertion(page)).resolves.toBeUndefined();
166211
});
212+
213+
it("fails when neither idiomatic re-mount nor legacy banner-flip happens", async () => {
214+
const { page, fakeClick } = makePage({
215+
signOutButtonVisible: true,
216+
signInCardRemounts: false,
217+
legacyBannerFlipsToUnauth: false,
218+
});
219+
const assertion = buildAuthAssertion({
220+
signOutTimeoutMs: 100,
221+
detectTimeoutMs: 50,
222+
click: fakeClick,
223+
});
224+
await expect(assertion(page)).rejects.toThrow(
225+
/neither idiomatic SignInCard re-mount nor legacy banner-flip/,
226+
);
227+
});
228+
229+
it("fails when legacy banner flips but error surface never appears", async () => {
230+
const { page, fakeClick } = makePage({
231+
signInButtonVisible: false,
232+
signOutButtonVisible: true,
233+
signInCardRemounts: false,
234+
legacyBannerFlipsToUnauth: true,
235+
legacyErrorSurfaceAppears: false,
236+
});
237+
const assertion = buildAuthAssertion({
238+
signOutTimeoutMs: 200,
239+
detectTimeoutMs: 50,
240+
click: fakeClick,
241+
});
242+
await expect(assertion(page)).rejects.toThrow(
243+
/legacy shape.*neither.*appeared/,
244+
);
245+
});
167246
});
168247
});

0 commit comments

Comments
 (0)