@agent-native/toolkit 0.208.0 → 0.209.0-nightly-20261014070126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/chat/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/MultiTabAssistantChat.js +12 -1
- package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
- package/dist/app/chat/agentkit-chat/guided-questions.d.ts +12 -0
- package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/guided-questions.js +32 -4
- package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
- package/dist/app/chat/agentkit-chat/index.d.ts +1 -1
- package/dist/app/chat/agentkit-chat/index.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/index.js +1 -1
- package/dist/app/chat/agentkit-chat/index.js.map +1 -1
- package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
- package/dist/app/chat/chat/run-recovery.js +15 -8
- package/dist/app/chat/chat/run-recovery.js.map +1 -1
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +66 -73
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/app/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/app/sharing/ShareDialog.js +4 -12
- package/dist/app/sharing/ShareDialog.js.map +1 -1
- package/dist/sharing/ShareControls.d.ts +19 -1
- package/dist/sharing/ShareControls.d.ts.map +1 -1
- package/dist/sharing/ShareControls.js +14 -7
- package/dist/sharing/ShareControls.js.map +1 -1
- package/dist/sharing/SharePrimitives.js +1 -1
- package/dist/sharing/SharePrimitives.js.map +1 -1
- package/dist/sharing/index.d.ts +1 -1
- package/dist/sharing/index.d.ts.map +1 -1
- package/dist/sharing/index.js +1 -1
- package/dist/sharing/index.js.map +1 -1
- package/package.json +4 -4
- package/src/app/chat/MultiTabAssistantChat.spec.tsx +101 -2
- package/src/app/chat/MultiTabAssistantChat.tsx +14 -1
- package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +168 -0
- package/src/app/chat/agentkit-chat/guided-questions.tsx +54 -9
- package/src/app/chat/agentkit-chat/index.ts +2 -0
- package/src/app/chat/chat/run-recovery.spec.tsx +64 -0
- package/src/app/chat/chat/run-recovery.tsx +14 -8
- package/src/app/sharing/ShareButton.spec.tsx +125 -32
- package/src/app/sharing/ShareButton.tsx +119 -149
- package/src/app/sharing/ShareDialog.spec.tsx +31 -0
- package/src/app/sharing/ShareDialog.tsx +46 -71
- package/src/sharing/ShareControls.spec.tsx +86 -1
- package/src/sharing/ShareControls.tsx +83 -27
- package/src/sharing/SharePrimitives.tsx +1 -1
- package/src/sharing/index.ts +4 -0
|
@@ -1097,6 +1097,35 @@ export type PendingQuestionRefetchResult =
|
|
|
1097
1097
|
| { status: "none" }
|
|
1098
1098
|
| { status: "error"; error: unknown };
|
|
1099
1099
|
|
|
1100
|
+
/**
|
|
1101
|
+
* Window event dispatched once per human submit of a guided question card,
|
|
1102
|
+
* only when the flow's `onSubmitMessage` resolves `{ delivered: true }`, so apps can
|
|
1103
|
+
* observe answers (for example, which option was picked) without owning the
|
|
1104
|
+
* flow.
|
|
1105
|
+
*/
|
|
1106
|
+
export const GUIDED_QUESTIONS_SUBMITTED_EVENT =
|
|
1107
|
+
"agentNative.guidedQuestionsSubmitted";
|
|
1108
|
+
|
|
1109
|
+
export interface GuidedQuestionsSubmittedDetail {
|
|
1110
|
+
stateKey: string;
|
|
1111
|
+
questions: GuidedQuestion[];
|
|
1112
|
+
answers: GuidedQuestionAnswers;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
function announceGuidedQuestionsSubmitted(
|
|
1116
|
+
detail: GuidedQuestionsSubmittedDetail,
|
|
1117
|
+
): void {
|
|
1118
|
+
// Listeners are observers; a throwing one must never block the submit.
|
|
1119
|
+
try {
|
|
1120
|
+
if (typeof window === "undefined") return;
|
|
1121
|
+
window.dispatchEvent(
|
|
1122
|
+
new CustomEvent(GUIDED_QUESTIONS_SUBMITTED_EVENT, { detail }),
|
|
1123
|
+
);
|
|
1124
|
+
} catch {
|
|
1125
|
+
// coercion-ok: an observer failure must not affect delivering the answers.
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1100
1129
|
function payloadBelongsToThread(
|
|
1101
1130
|
payload: GuidedQuestionPayload,
|
|
1102
1131
|
threadId: string | undefined,
|
|
@@ -1241,9 +1270,13 @@ export function useGuidedQuestionFlow({
|
|
|
1241
1270
|
}, [queryClient, resolvedQueryKey, scopedKey, stateKey]);
|
|
1242
1271
|
|
|
1243
1272
|
const sendAndClearOnDelivery = useCallback(
|
|
1244
|
-
(
|
|
1273
|
+
(
|
|
1274
|
+
send: () => void | Promise<{ delivered: boolean }>,
|
|
1275
|
+
onDelivered?: () => void,
|
|
1276
|
+
) => {
|
|
1245
1277
|
if (submissionInFlightRef.current) return;
|
|
1246
1278
|
const result = send();
|
|
1279
|
+
// A synchronous send reports no delivery, so it is never announced.
|
|
1247
1280
|
if (!result) {
|
|
1248
1281
|
clear();
|
|
1249
1282
|
return;
|
|
@@ -1252,7 +1285,9 @@ export function useGuidedQuestionFlow({
|
|
|
1252
1285
|
setIsSubmitting(true);
|
|
1253
1286
|
void result
|
|
1254
1287
|
.then(({ delivered }) => {
|
|
1255
|
-
if (delivered)
|
|
1288
|
+
if (!delivered) return;
|
|
1289
|
+
onDelivered?.();
|
|
1290
|
+
clear();
|
|
1256
1291
|
})
|
|
1257
1292
|
.catch((error) => {
|
|
1258
1293
|
console.error("Guided question submission failed", error);
|
|
@@ -1276,6 +1311,12 @@ export function useGuidedQuestionFlow({
|
|
|
1276
1311
|
return;
|
|
1277
1312
|
}
|
|
1278
1313
|
if (isSubmissionBlocked) return;
|
|
1314
|
+
const announce = () =>
|
|
1315
|
+
announceGuidedQuestionsSubmitted({
|
|
1316
|
+
stateKey,
|
|
1317
|
+
questions: visiblePayload?.questions ?? [],
|
|
1318
|
+
answers,
|
|
1319
|
+
});
|
|
1279
1320
|
const formattedAnswers = formatGuidedAnswersForAgent(
|
|
1280
1321
|
answers,
|
|
1281
1322
|
visiblePayload?.questions,
|
|
@@ -1292,15 +1333,18 @@ export function useGuidedQuestionFlow({
|
|
|
1292
1333
|
.filter(Boolean)
|
|
1293
1334
|
.join("\n\n");
|
|
1294
1335
|
if (onSubmitMessage) {
|
|
1295
|
-
sendAndClearOnDelivery(
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1336
|
+
sendAndClearOnDelivery(
|
|
1337
|
+
() =>
|
|
1338
|
+
onSubmitMessage({
|
|
1339
|
+
answers,
|
|
1340
|
+
formattedAnswers,
|
|
1341
|
+
message: resolvedSubmitMessage,
|
|
1342
|
+
context,
|
|
1343
|
+
}),
|
|
1344
|
+
announce,
|
|
1302
1345
|
);
|
|
1303
1346
|
} else {
|
|
1347
|
+
// Fire-and-forget: there is no delivery signal to announce on.
|
|
1304
1348
|
sendToAgentChat({
|
|
1305
1349
|
message: resolvedSubmitMessage,
|
|
1306
1350
|
context,
|
|
@@ -1315,6 +1359,7 @@ export function useGuidedQuestionFlow({
|
|
|
1315
1359
|
onSubmitMessage,
|
|
1316
1360
|
sendAndClearOnDelivery,
|
|
1317
1361
|
isSubmissionBlocked,
|
|
1362
|
+
stateKey,
|
|
1318
1363
|
visiblePayload,
|
|
1319
1364
|
submitMessage,
|
|
1320
1365
|
],
|
|
@@ -6,6 +6,7 @@ export {
|
|
|
6
6
|
} from "./questions.js";
|
|
7
7
|
export {
|
|
8
8
|
askUserQuestion,
|
|
9
|
+
GUIDED_QUESTIONS_SUBMITTED_EVENT,
|
|
9
10
|
formatGuidedAnswerValue,
|
|
10
11
|
formatGuidedAnswersForAgent,
|
|
11
12
|
getOtherGuidedAnswerText,
|
|
@@ -23,6 +24,7 @@ export {
|
|
|
23
24
|
type GuidedQuestionOption,
|
|
24
25
|
type GuidedQuestionPayload,
|
|
25
26
|
type GuidedQuestionType,
|
|
27
|
+
type GuidedQuestionsSubmittedDetail,
|
|
26
28
|
type UseGuidedQuestionFlowOptions,
|
|
27
29
|
} from "./guided-questions.js";
|
|
28
30
|
export { AgentKitActionWidget } from "./action-widget.js";
|
|
@@ -1076,6 +1076,70 @@ describe("run recovery surfaces", () => {
|
|
|
1076
1076
|
);
|
|
1077
1077
|
});
|
|
1078
1078
|
|
|
1079
|
+
it("keeps the setup card working when setup tracking throws", async () => {
|
|
1080
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
1081
|
+
setupTelemetryMock.mockImplementation(() => {
|
|
1082
|
+
throw new Error("tracker exploded");
|
|
1083
|
+
});
|
|
1084
|
+
const onConnected = vi.fn();
|
|
1085
|
+
const router = createMemoryRouter(
|
|
1086
|
+
[
|
|
1087
|
+
{
|
|
1088
|
+
path: "/home",
|
|
1089
|
+
element: (
|
|
1090
|
+
<AgentNativeI18nProvider
|
|
1091
|
+
initialLocale="en-US"
|
|
1092
|
+
initialPreference="en-US"
|
|
1093
|
+
persistPreference={false}
|
|
1094
|
+
>
|
|
1095
|
+
<BuilderSetupCard onConnected={onConnected} />
|
|
1096
|
+
</AgentNativeI18nProvider>
|
|
1097
|
+
),
|
|
1098
|
+
},
|
|
1099
|
+
{ path: "/settings/keys", element: <SetupTrackingFlowProbe /> },
|
|
1100
|
+
],
|
|
1101
|
+
{ initialEntries: ["/home"] },
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1104
|
+
await act(async () => {
|
|
1105
|
+
root.render(<RouterProvider router={router} />);
|
|
1106
|
+
});
|
|
1107
|
+
expect(container.querySelector(".agent-builder-setup-card")).not.toBeNull();
|
|
1108
|
+
|
|
1109
|
+
await act(async () => {
|
|
1110
|
+
container
|
|
1111
|
+
.querySelector<HTMLButtonElement>(
|
|
1112
|
+
".agent-builder-setup-card__builder-button",
|
|
1113
|
+
)
|
|
1114
|
+
?.click();
|
|
1115
|
+
});
|
|
1116
|
+
await vi.waitFor(() =>
|
|
1117
|
+
expect(builderConnectMock.onConnect).toBeTypeOf("function"),
|
|
1118
|
+
);
|
|
1119
|
+
await act(async () => builderConnectMock.onConnect?.(true));
|
|
1120
|
+
await act(async () => {
|
|
1121
|
+
await expect(
|
|
1122
|
+
builderFlowMock.onConnected?.({ orgName: null }),
|
|
1123
|
+
).resolves.toBeUndefined();
|
|
1124
|
+
});
|
|
1125
|
+
expect(onConnected).toHaveBeenCalledTimes(1);
|
|
1126
|
+
|
|
1127
|
+
await act(async () => {
|
|
1128
|
+
container
|
|
1129
|
+
.querySelector<HTMLAnchorElement>('a[href="/settings/keys"]')
|
|
1130
|
+
?.click();
|
|
1131
|
+
await Promise.resolve();
|
|
1132
|
+
});
|
|
1133
|
+
expect(router.state.location.pathname).toBe("/settings/keys");
|
|
1134
|
+
expect(setupTelemetryMock.mock.calls.map(([name]) => name)).toEqual([
|
|
1135
|
+
"integration_setup_exposed",
|
|
1136
|
+
"integration_method_clicked",
|
|
1137
|
+
"integration_method_outcome",
|
|
1138
|
+
"integration_method_clicked",
|
|
1139
|
+
]);
|
|
1140
|
+
expect(warn).toHaveBeenCalled();
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1079
1143
|
it("tracks Builder success only after a selected setup attempt is confirmed", async () => {
|
|
1080
1144
|
const card = (
|
|
1081
1145
|
<AgentNativeI18nProvider
|
|
@@ -82,14 +82,20 @@ function trackSetupFunnelEvent(
|
|
|
82
82
|
action: SetupTelemetryAction,
|
|
83
83
|
outcome: SetupTelemetryOutcome,
|
|
84
84
|
): void {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
85
|
+
// Runs in the card's mount effect and ahead of the setup links' navigation,
|
|
86
|
+
// so a throw here would unmount the card or swallow the click.
|
|
87
|
+
try {
|
|
88
|
+
trackOnboardingEvent(eventName, {
|
|
89
|
+
flow: "chat_setup",
|
|
90
|
+
app_name: setupTelemetryAppName(),
|
|
91
|
+
step_id: "connect_ai",
|
|
92
|
+
method_id: methodId,
|
|
93
|
+
action,
|
|
94
|
+
outcome,
|
|
95
|
+
});
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.warn(`[connect-ai-setup] ${eventName} tracking failed:`, err);
|
|
98
|
+
}
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
type BuilderConnectTelemetryAttempt = {
|
|
@@ -92,7 +92,7 @@ vi.mock("@agent-native/toolkit/ui/popover", () => {
|
|
|
92
92
|
string,
|
|
93
93
|
unknown
|
|
94
94
|
>;
|
|
95
|
-
return String(props.className ?? "").includes("w-[
|
|
95
|
+
return String(props.className ?? "").includes("w-[360px]");
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
return {
|
|
@@ -191,6 +191,15 @@ function setInputValue(
|
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
// Radix tabs activate on mousedown, like a real pointer press.
|
|
195
|
+
function pressTab(tab: HTMLElement) {
|
|
196
|
+
act(() => {
|
|
197
|
+
tab.dispatchEvent(
|
|
198
|
+
new MouseEvent("mousedown", { bubbles: true, button: 0 }),
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
194
203
|
describe("ShareButton", () => {
|
|
195
204
|
let container: HTMLDivElement;
|
|
196
205
|
let root: Root;
|
|
@@ -265,8 +274,8 @@ describe("ShareButton", () => {
|
|
|
265
274
|
) as HTMLInputElement;
|
|
266
275
|
setInputValue(input, "first@example.com");
|
|
267
276
|
|
|
268
|
-
const add =
|
|
269
|
-
|
|
277
|
+
const add = container.querySelector<HTMLButtonElement>(
|
|
278
|
+
'button[aria-label="Add"]',
|
|
270
279
|
);
|
|
271
280
|
if (!add) throw new Error("Add button not found");
|
|
272
281
|
|
|
@@ -323,8 +332,8 @@ describe("ShareButton", () => {
|
|
|
323
332
|
'input[placeholder="Add people by email"]',
|
|
324
333
|
) as HTMLInputElement;
|
|
325
334
|
setInputValue(input, "commenter@example.com");
|
|
326
|
-
const add =
|
|
327
|
-
|
|
335
|
+
const add = container.querySelector<HTMLButtonElement>(
|
|
336
|
+
'button[aria-label="Add"]',
|
|
328
337
|
);
|
|
329
338
|
if (!add) throw new Error("Add button not found");
|
|
330
339
|
|
|
@@ -391,8 +400,8 @@ describe("ShareButton", () => {
|
|
|
391
400
|
) as HTMLTextAreaElement;
|
|
392
401
|
setInputValue(message, "Here is the latest version.");
|
|
393
402
|
|
|
394
|
-
const add =
|
|
395
|
-
|
|
403
|
+
const add = container.querySelector<HTMLButtonElement>(
|
|
404
|
+
'button[aria-label="Add"]',
|
|
396
405
|
);
|
|
397
406
|
if (!add) throw new Error("Add button not found");
|
|
398
407
|
act(() => add.click());
|
|
@@ -406,6 +415,55 @@ describe("ShareButton", () => {
|
|
|
406
415
|
);
|
|
407
416
|
});
|
|
408
417
|
|
|
418
|
+
it("keeps the invite row compact with the role inside the field and an icon-only Add", async () => {
|
|
419
|
+
await act(async () => {
|
|
420
|
+
root.render(
|
|
421
|
+
<QueryClientProvider client={queryClient}>
|
|
422
|
+
<ShareButton resourceType="document" resourceId="doc-1" />
|
|
423
|
+
</QueryClientProvider>,
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
const input = container.querySelector<HTMLInputElement>(
|
|
428
|
+
'input[placeholder="Add people by email"]',
|
|
429
|
+
);
|
|
430
|
+
const field = input?.parentElement;
|
|
431
|
+
const role = container.querySelector('button[aria-label="Role"]');
|
|
432
|
+
const add = container.querySelector<HTMLButtonElement>(
|
|
433
|
+
'button[aria-label="Add"]',
|
|
434
|
+
);
|
|
435
|
+
expect(field?.contains(role ?? null)).toBe(true);
|
|
436
|
+
expect(field?.contains(add)).toBe(false);
|
|
437
|
+
expect(add?.textContent).toBe("");
|
|
438
|
+
expect(add?.querySelector("svg")).not.toBeNull();
|
|
439
|
+
expect(add?.getAttribute("title")).toBe("Add");
|
|
440
|
+
expect(add?.disabled).toBe(true);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it("renders the compact 360px popover and lets a host raise its layer", async () => {
|
|
444
|
+
await act(async () => {
|
|
445
|
+
root.render(
|
|
446
|
+
<QueryClientProvider client={queryClient}>
|
|
447
|
+
<ShareButton
|
|
448
|
+
resourceType="design"
|
|
449
|
+
resourceId="design-1"
|
|
450
|
+
popoverClassName="z-[100010]"
|
|
451
|
+
/>
|
|
452
|
+
</QueryClientProvider>,
|
|
453
|
+
);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const popover = Array.from(
|
|
457
|
+
container.querySelectorAll<HTMLElement>(
|
|
458
|
+
"[data-agent-native-share-overlay]",
|
|
459
|
+
),
|
|
460
|
+
).find((node) => node.className.includes("w-[360px]"));
|
|
461
|
+
expect(popover).toBeDefined();
|
|
462
|
+
expect(popover?.className).toContain("z-[100010]");
|
|
463
|
+
expect(popover?.className).not.toContain("z-[2000]");
|
|
464
|
+
expect(popover?.className).not.toContain("460px");
|
|
465
|
+
});
|
|
466
|
+
|
|
409
467
|
it("keeps a draft email when the share popover is closed and reopened", async () => {
|
|
410
468
|
popoverTestState.simulateMounting = true;
|
|
411
469
|
|
|
@@ -954,31 +1012,68 @@ describe("ShareButton", () => {
|
|
|
954
1012
|
);
|
|
955
1013
|
});
|
|
956
1014
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
expect(
|
|
1015
|
+
const tabs = Array.from(
|
|
1016
|
+
container.querySelectorAll<HTMLButtonElement>('[role="tab"]'),
|
|
1017
|
+
);
|
|
1018
|
+
expect(tabs.map((tab) => tab.textContent)).toEqual([
|
|
1019
|
+
"Share link",
|
|
1020
|
+
"Export",
|
|
1021
|
+
"Send to...",
|
|
1022
|
+
"Context",
|
|
1023
|
+
]);
|
|
1024
|
+
expect(tabs[0].getAttribute("aria-selected")).toBe("true");
|
|
1025
|
+
expect(
|
|
1026
|
+
container.querySelector('[role="tablist"]')?.getAttribute("aria-label"),
|
|
1027
|
+
).toBe("Share options");
|
|
961
1028
|
expect(container.textContent).not.toContain("Context body");
|
|
962
1029
|
expect(container.textContent).not.toContain("Export body");
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
).not.toBeNull();
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
const exportTab = Array.from(container.querySelectorAll("button")).find(
|
|
972
|
-
(button) => button.textContent === "Export",
|
|
973
|
-
);
|
|
974
|
-
if (!exportTab) throw new Error("Export tab not found");
|
|
1030
|
+
expect(
|
|
1031
|
+
container
|
|
1032
|
+
.querySelector('[role="tabpanel"]')
|
|
1033
|
+
?.getAttribute("aria-labelledby"),
|
|
1034
|
+
).toBe(tabs[0].id);
|
|
975
1035
|
|
|
976
|
-
|
|
977
|
-
exportTab.click();
|
|
978
|
-
});
|
|
1036
|
+
pressTab(tabs[1]);
|
|
979
1037
|
|
|
1038
|
+
expect(tabs[1].getAttribute("aria-selected")).toBe("true");
|
|
980
1039
|
expect(container.textContent).toContain("Export body");
|
|
981
1040
|
expect(container.textContent).not.toContain("Send body");
|
|
1041
|
+
expect(container.textContent).not.toContain("Add people by email");
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
it("draws every share tab, including app-owned ones, as an underline tab", async () => {
|
|
1045
|
+
await act(async () => {
|
|
1046
|
+
root.render(
|
|
1047
|
+
<QueryClientProvider client={queryClient}>
|
|
1048
|
+
<ShareButton
|
|
1049
|
+
resourceType="design"
|
|
1050
|
+
resourceId="design-1"
|
|
1051
|
+
shareTabs={{
|
|
1052
|
+
tabs: [
|
|
1053
|
+
{
|
|
1054
|
+
value: "export",
|
|
1055
|
+
label: "Export",
|
|
1056
|
+
content: <div>Export body</div>,
|
|
1057
|
+
},
|
|
1058
|
+
],
|
|
1059
|
+
}}
|
|
1060
|
+
/>
|
|
1061
|
+
</QueryClientProvider>,
|
|
1062
|
+
);
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
const list = container.querySelector<HTMLElement>('[role="tablist"]');
|
|
1066
|
+
expect(list?.className).toContain("bg-transparent");
|
|
1067
|
+
expect(list?.className).not.toContain("bg-muted");
|
|
1068
|
+
const tabs = Array.from(
|
|
1069
|
+
container.querySelectorAll<HTMLElement>('[role="tab"]'),
|
|
1070
|
+
);
|
|
1071
|
+
expect(tabs).toHaveLength(2);
|
|
1072
|
+
for (const tab of tabs) {
|
|
1073
|
+
expect(tab.className).toContain("after:h-0.5");
|
|
1074
|
+
expect(tab.className).toContain("data-[state=active]:bg-transparent");
|
|
1075
|
+
expect(tab.className).not.toContain("shadow-sm");
|
|
1076
|
+
}
|
|
982
1077
|
});
|
|
983
1078
|
|
|
984
1079
|
it("renders the context tab when it is the only custom share tab", async () => {
|
|
@@ -1007,14 +1102,12 @@ describe("ShareButton", () => {
|
|
|
1007
1102
|
expect(container.textContent).not.toContain("Context body");
|
|
1008
1103
|
expect(container.querySelector('[role="tablist"]')).not.toBeNull();
|
|
1009
1104
|
|
|
1010
|
-
const contextTab = Array.from(
|
|
1011
|
-
(
|
|
1012
|
-
);
|
|
1105
|
+
const contextTab = Array.from(
|
|
1106
|
+
container.querySelectorAll<HTMLElement>('[role="tab"]'),
|
|
1107
|
+
).find((tab) => tab.textContent === "Context");
|
|
1013
1108
|
if (!contextTab) throw new Error("Context tab not found");
|
|
1014
1109
|
|
|
1015
|
-
|
|
1016
|
-
contextTab.click();
|
|
1017
|
-
});
|
|
1110
|
+
pressTab(contextTab);
|
|
1018
1111
|
|
|
1019
1112
|
expect(container.textContent).toContain("Context body");
|
|
1020
1113
|
const contextPanelId = contextTab.getAttribute("aria-controls");
|