@agent-native/toolkit 0.204.0 → 0.204.1-nightly-20261008034100
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/agent-page/AgentJobsTab.d.ts.map +1 -1
- package/dist/app/agent-page/AgentJobsTab.js +4 -2
- package/dist/app/agent-page/AgentJobsTab.js.map +1 -1
- package/dist/app/agent-page/AutomationDetailsDialog.d.ts +2 -1
- package/dist/app/agent-page/AutomationDetailsDialog.d.ts.map +1 -1
- package/dist/app/agent-page/AutomationDetailsDialog.js +8 -4
- package/dist/app/agent-page/AutomationDetailsDialog.js.map +1 -1
- package/dist/app/agent-page/ScheduledTriggerNotice.d.ts.map +1 -1
- package/dist/app/agent-page/ScheduledTriggerNotice.js +41 -19
- package/dist/app/agent-page/ScheduledTriggerNotice.js.map +1 -1
- package/dist/app/agent-page/use-jobs.d.ts +1 -1
- package/dist/app/agent-page/use-jobs.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +124 -45
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +22 -1
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +14 -1
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/root.d.ts +3 -2
- package/dist/app/agentkit/react/root.d.ts.map +1 -1
- package/dist/app/agentkit/react/root.js +2 -2
- package/dist/app/agentkit/react/root.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +32 -2
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +28 -3
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/AgentPanel.js +1 -1
- package/dist/app/chat/AgentPanel.js.map +1 -1
- package/dist/app/chat/RunStuckBanner.d.ts +8 -1
- package/dist/app/chat/RunStuckBanner.d.ts.map +1 -1
- package/dist/app/chat/RunStuckBanner.js +68 -6
- package/dist/app/chat/RunStuckBanner.js.map +1 -1
- package/dist/app/chat/chat/run-recovery.d.ts +4 -2
- package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
- package/dist/app/chat/chat/run-recovery.js +3 -3
- package/dist/app/chat/chat/run-recovery.js.map +1 -1
- package/dist/app/chat/composer/use-mention-search.d.ts +1 -0
- package/dist/app/chat/composer/use-mention-search.d.ts.map +1 -1
- package/dist/app/chat/feedback-report.d.ts +12 -0
- package/dist/app/chat/feedback-report.d.ts.map +1 -0
- package/dist/app/chat/feedback-report.js +21 -0
- package/dist/app/chat/feedback-report.js.map +1 -0
- package/dist/app/chat/reconcile-settled-run.d.ts +15 -0
- package/dist/app/chat/reconcile-settled-run.d.ts.map +1 -0
- package/dist/app/chat/reconcile-settled-run.js +41 -0
- package/dist/app/chat/reconcile-settled-run.js.map +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +9 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +9 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +9 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +9 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +9 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +9 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +9 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +9 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +9 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +9 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +9 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +9 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/settings/shell/pages/audit.d.ts.map +1 -1
- package/dist/app/settings/shell/pages/audit.js +11 -2
- package/dist/app/settings/shell/pages/audit.js.map +1 -1
- package/dist/composer/ComposerContextMenu.d.ts +14 -1
- package/dist/composer/ComposerContextMenu.d.ts.map +1 -1
- package/dist/composer/ComposerContextMenu.js +65 -19
- package/dist/composer/ComposerContextMenu.js.map +1 -1
- package/dist/composer/MentionPopover.d.ts.map +1 -1
- package/dist/composer/MentionPopover.js +3 -3
- package/dist/composer/MentionPopover.js.map +1 -1
- package/dist/composer/PromptComposer.d.ts +1 -1
- package/dist/composer/PromptComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.d.ts +2 -2
- package/dist/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.js +92 -36
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/composer/use-mention-search.d.ts +1 -0
- package/dist/composer/use-mention-search.d.ts.map +1 -1
- package/dist/composer/use-mention-search.js +8 -1
- package/dist/composer/use-mention-search.js.map +1 -1
- package/package.json +4 -4
- package/src/app/agent-page/AgentJobsTab.blocked.spec.tsx +43 -0
- package/src/app/agent-page/AgentJobsTab.tsx +14 -5
- package/src/app/agent-page/AutomationDetailsDialog.tsx +22 -8
- package/src/app/agent-page/ScheduledTriggerNotice.spec.tsx +45 -3
- package/src/app/agent-page/ScheduledTriggerNotice.tsx +52 -31
- package/src/app/agent-page/use-jobs.ts +1 -1
- package/src/app/agentkit/react/components.interaction.spec.tsx +311 -1
- package/src/app/agentkit/react/components.spec.tsx +106 -2
- package/src/app/agentkit/react/components.tsx +217 -80
- package/src/app/agentkit/react/context.tsx +36 -0
- package/src/app/agentkit/react/root.tsx +4 -0
- package/src/app/agentkit/react/styles.css +32 -2
- package/src/app/chat/AgentKitAssistantChat.tsx +35 -2
- package/src/app/chat/AgentPanel.header.spec.ts +43 -7
- package/src/app/chat/AgentPanel.tsx +1 -1
- package/src/app/chat/RunStuckBanner.spec.tsx +258 -17
- package/src/app/chat/RunStuckBanner.tsx +107 -5
- package/src/app/chat/chat/run-recovery.tsx +10 -2
- package/src/app/chat/feedback-report.spec.ts +45 -0
- package/src/app/chat/feedback-report.ts +27 -0
- package/src/app/chat/reconcile-settled-run.spec.ts +112 -0
- package/src/app/chat/reconcile-settled-run.ts +57 -0
- package/src/app/i18n/catalogs/ar-SA.ts +12 -0
- package/src/app/i18n/catalogs/de-DE.ts +12 -0
- package/src/app/i18n/catalogs/en-US.ts +12 -0
- package/src/app/i18n/catalogs/es-ES.ts +12 -0
- package/src/app/i18n/catalogs/fr-FR.ts +12 -0
- package/src/app/i18n/catalogs/hi-IN.ts +12 -0
- package/src/app/i18n/catalogs/ja-JP.ts +12 -0
- package/src/app/i18n/catalogs/ko-KR.ts +12 -0
- package/src/app/i18n/catalogs/pt-BR.ts +12 -0
- package/src/app/i18n/catalogs/zh-CN.ts +10 -0
- package/src/app/i18n/catalogs/zh-TW.ts +10 -0
- package/src/app/settings/shell/pages/audit.spec.tsx +30 -0
- package/src/app/settings/shell/pages/audit.tsx +12 -1
- package/src/composer/ComposerContextMenu.tsx +94 -22
- package/src/composer/ComposerPlusMenu.parity.spec.tsx +218 -233
- package/src/composer/MentionPopover.tsx +12 -3
- package/src/composer/PromptComposer.context.spec.tsx +526 -195
- package/src/composer/PromptComposer.tsx +1 -1
- package/src/composer/TiptapComposer.tsx +105 -37
- package/src/composer/use-mention-search.ts +8 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
|
|
3
|
+
import type { Editor } from "@tiptap/core";
|
|
3
4
|
import React, { act } from "react";
|
|
4
5
|
import { createRoot, type Root } from "react-dom/client";
|
|
5
6
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
@@ -109,74 +110,400 @@ describe("controlled composer context", () => {
|
|
|
109
110
|
container.querySelector('button[aria-label="Add context"]'),
|
|
110
111
|
).toBeNull();
|
|
111
112
|
});
|
|
112
|
-
|
|
113
|
+
// Types like a browser: the editor's keydown handlers run first, and only a
|
|
114
|
+
// key they leave unhandled reaches the document.
|
|
115
|
+
async function typeInto(editor: HTMLElement, text: string) {
|
|
116
|
+
const { view } = (editor as HTMLElement & { editor: Editor }).editor;
|
|
117
|
+
for (const key of text) {
|
|
118
|
+
await act(async () => {
|
|
119
|
+
const event = new KeyboardEvent("keydown", {
|
|
120
|
+
key,
|
|
121
|
+
bubbles: true,
|
|
122
|
+
cancelable: true,
|
|
123
|
+
});
|
|
124
|
+
editor.dispatchEvent(event);
|
|
125
|
+
if (!event.defaultPrevented)
|
|
126
|
+
view.dispatch(view.state.tr.insertText(key));
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function pressEnter(editor: HTMLElement) {
|
|
132
|
+
await pressKey(editor, "Enter");
|
|
133
|
+
}
|
|
134
|
+
async function pressKey(editor: HTMLElement, key: string) {
|
|
135
|
+
await act(async () => {
|
|
136
|
+
editor.dispatchEvent(
|
|
137
|
+
new KeyboardEvent("keydown", {
|
|
138
|
+
key,
|
|
139
|
+
bubbles: true,
|
|
140
|
+
cancelable: true,
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
143
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const slidesAgent = {
|
|
147
|
+
id: "agent:slides",
|
|
148
|
+
label: "Slides",
|
|
149
|
+
description: "Presentations in this workspace",
|
|
150
|
+
section: "Connected Agents",
|
|
151
|
+
source: "agent",
|
|
152
|
+
refType: "agent",
|
|
153
|
+
refId: "slides",
|
|
154
|
+
refPath: "https://slides.example.test",
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
it("keeps a typed @ address as text and submits it", async () => {
|
|
158
|
+
vi.stubGlobal(
|
|
159
|
+
"fetch",
|
|
160
|
+
vi.fn(async () => new Response('{"items":[]}\n', { status: 200 })),
|
|
161
|
+
);
|
|
162
|
+
const { onSubmit } = await mount({
|
|
163
|
+
initialText: "",
|
|
164
|
+
contextMenuItems: [
|
|
165
|
+
{ id: "source", label: "Choose source", onSelect() {} },
|
|
166
|
+
],
|
|
167
|
+
mentionItems: [slidesAgent],
|
|
168
|
+
});
|
|
169
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
170
|
+
await act(async () => editor.focus());
|
|
171
|
+
|
|
172
|
+
await typeInto(editor, "Ping a @builder.io");
|
|
173
|
+
await act(async () => new Promise((resolve) => setTimeout(resolve, 250)));
|
|
174
|
+
await typeInto(editor, " email");
|
|
175
|
+
|
|
176
|
+
expect(document.querySelector('[role="menu"]')).toBeNull();
|
|
177
|
+
expect(
|
|
178
|
+
document.querySelector('[data-agent-native-mention-popover="true"]'),
|
|
179
|
+
).toBeNull();
|
|
180
|
+
expect(editor.textContent).toBe("Ping a @builder.io email");
|
|
181
|
+
await pressEnter(editor);
|
|
182
|
+
expect(onSubmit).toHaveBeenCalledOnce();
|
|
183
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Ping a @builder.io email");
|
|
184
|
+
});
|
|
185
|
+
it("submits a typed @ that nothing matches on Enter", async () => {
|
|
186
|
+
const { onSubmit } = await mount({
|
|
187
|
+
initialText: "",
|
|
188
|
+
includeDefaultMentionSearch: false,
|
|
189
|
+
mentionItems: [slidesAgent],
|
|
190
|
+
});
|
|
191
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
192
|
+
await act(async () => editor.focus());
|
|
193
|
+
|
|
194
|
+
await typeInto(editor, "Reply @");
|
|
195
|
+
expect(
|
|
196
|
+
document.querySelector('[data-agent-native-mention-popover="true"]'),
|
|
197
|
+
).not.toBeNull();
|
|
198
|
+
await typeInto(editor, "x");
|
|
199
|
+
await pressEnter(editor);
|
|
200
|
+
|
|
201
|
+
expect(onSubmit).toHaveBeenCalledOnce();
|
|
202
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Reply @x");
|
|
203
|
+
});
|
|
204
|
+
it("keeps @ suggestions open for host mention items that arrive later", async () => {
|
|
205
|
+
await mount({
|
|
206
|
+
initialText: "",
|
|
207
|
+
includeDefaultMentionSearch: false,
|
|
208
|
+
mentionItems: [],
|
|
209
|
+
});
|
|
210
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
211
|
+
await act(async () => editor.focus());
|
|
212
|
+
|
|
213
|
+
await typeInto(editor, "Ask @Sli");
|
|
214
|
+
await mount({
|
|
215
|
+
initialText: "",
|
|
216
|
+
includeDefaultMentionSearch: false,
|
|
217
|
+
mentionItems: [slidesAgent],
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
expect(
|
|
221
|
+
document.querySelector('[data-mention-index="0"]')?.textContent,
|
|
222
|
+
).toContain("Slides");
|
|
223
|
+
});
|
|
224
|
+
it.each([
|
|
225
|
+
["finds nothing", '{"items":[]}\n', 200, null],
|
|
226
|
+
["fails", "", 500, "open"],
|
|
227
|
+
] as const)(
|
|
228
|
+
"ends a typed @ query only when the mention search %s",
|
|
229
|
+
async (_case, body, status, popoverAfterSearch) => {
|
|
230
|
+
vi.stubGlobal(
|
|
231
|
+
"fetch",
|
|
232
|
+
vi.fn(async () => new Response(body, { status })),
|
|
233
|
+
);
|
|
234
|
+
const { onSubmit } = await mount({ initialText: "" });
|
|
235
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
236
|
+
await act(async () => editor.focus());
|
|
237
|
+
|
|
238
|
+
await typeInto(editor, "Reply @x");
|
|
239
|
+
await act(async () => new Promise((resolve) => setTimeout(resolve, 250)));
|
|
240
|
+
|
|
241
|
+
// A failed search is unknown, not empty, so the popover stays open.
|
|
242
|
+
expect(
|
|
243
|
+
document.querySelector('[data-agent-native-mention-popover="true"]')
|
|
244
|
+
? "open"
|
|
245
|
+
: null,
|
|
246
|
+
).toBe(popoverAfterSearch);
|
|
247
|
+
await pressEnter(editor);
|
|
248
|
+
expect(onSubmit).toHaveBeenCalledOnce();
|
|
249
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Reply @x");
|
|
250
|
+
},
|
|
251
|
+
);
|
|
252
|
+
it.each(["Enter", "Tab"])(
|
|
253
|
+
"turns a typed @ query into a mention when %s picks it",
|
|
254
|
+
async (key) => {
|
|
255
|
+
const onReferencesChange = vi.fn();
|
|
256
|
+
const { onSubmit } = await mount({
|
|
257
|
+
initialText: "",
|
|
258
|
+
contextMenuItems: [],
|
|
259
|
+
includeDefaultMentionSearch: false,
|
|
260
|
+
onReferencesChange,
|
|
261
|
+
mentionItems: [slidesAgent],
|
|
262
|
+
});
|
|
263
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
264
|
+
await act(async () => editor.focus());
|
|
265
|
+
|
|
266
|
+
await typeInto(editor, "Ask @Sli");
|
|
267
|
+
expect(document.querySelector('[role="menu"]')).toBeNull();
|
|
268
|
+
expect(
|
|
269
|
+
document.querySelector('[data-mention-index="0"]')?.textContent,
|
|
270
|
+
).toContain("Slides");
|
|
271
|
+
await pressKey(editor, key);
|
|
272
|
+
|
|
273
|
+
expect(editor.textContent).toContain("Ask ");
|
|
274
|
+
expect(editor.textContent).toContain("Slides");
|
|
275
|
+
expect(editor.textContent).not.toContain("@Sli");
|
|
276
|
+
expect(onReferencesChange).toHaveBeenLastCalledWith([
|
|
277
|
+
expect.objectContaining({ refType: "agent", refId: "slides" }),
|
|
278
|
+
]);
|
|
279
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
280
|
+
},
|
|
281
|
+
);
|
|
282
|
+
it("keeps an exactly matching @name followed by Space as text", async () => {
|
|
283
|
+
const onReferencesChange = vi.fn();
|
|
284
|
+
const { onSubmit } = await mount({
|
|
285
|
+
initialText: "",
|
|
286
|
+
contextMenuItems: [],
|
|
287
|
+
includeDefaultMentionSearch: false,
|
|
288
|
+
onReferencesChange,
|
|
289
|
+
mentionItems: [slidesAgent],
|
|
290
|
+
});
|
|
291
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
292
|
+
await act(async () => editor.focus());
|
|
293
|
+
|
|
294
|
+
await typeInto(editor, "Ask @Slides rock");
|
|
295
|
+
|
|
296
|
+
expect(editor.textContent).toBe("Ask @Slides rock");
|
|
297
|
+
expect(onReferencesChange).not.toHaveBeenCalledWith([
|
|
298
|
+
expect.objectContaining({ refId: "slides" }),
|
|
299
|
+
]);
|
|
300
|
+
await pressKey(editor, "Escape");
|
|
301
|
+
await pressEnter(editor);
|
|
302
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Ask @Slides rock");
|
|
303
|
+
});
|
|
304
|
+
it("suggests host context sources for a typed @ and attaches the one picked", async () => {
|
|
305
|
+
const onSelect = vi.fn();
|
|
306
|
+
const { onSubmit } = await mount({
|
|
307
|
+
initialText: "",
|
|
308
|
+
contextMenuItems: [
|
|
309
|
+
{
|
|
310
|
+
id: "design-context",
|
|
311
|
+
label: "Design context",
|
|
312
|
+
children: [{ id: "figma", label: "Figma", onSelect }],
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
includeDefaultMentionSearch: false,
|
|
316
|
+
mentionItems: [slidesAgent],
|
|
317
|
+
});
|
|
318
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
319
|
+
await act(async () => editor.focus());
|
|
320
|
+
|
|
321
|
+
await typeInto(editor, "Use @fig");
|
|
322
|
+
const popover = document.querySelector(
|
|
323
|
+
'[data-agent-native-mention-popover="true"]',
|
|
324
|
+
);
|
|
325
|
+
expect(popover?.textContent).toContain("Design context");
|
|
326
|
+
expect(popover?.textContent).toContain("Figma");
|
|
327
|
+
expect(popover?.textContent).not.toContain("Slides");
|
|
328
|
+
expect(document.activeElement).toBe(editor);
|
|
329
|
+
await pressEnter(editor);
|
|
330
|
+
|
|
331
|
+
expect(onSelect).toHaveBeenCalledOnce();
|
|
332
|
+
expect(editor.textContent).toBe("Use ");
|
|
333
|
+
expect(document.querySelector('[role="menu"]')).toBeNull();
|
|
334
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
335
|
+
});
|
|
336
|
+
it("opens a picked host picker as a dialog and attaches its choice", async () => {
|
|
113
337
|
const onSelect = vi.fn();
|
|
114
338
|
await mount({
|
|
115
339
|
initialText: "",
|
|
116
|
-
contextMenuItems: [
|
|
340
|
+
contextMenuItems: [
|
|
341
|
+
{
|
|
342
|
+
id: "documents",
|
|
343
|
+
label: "Documents",
|
|
344
|
+
children: [
|
|
345
|
+
{
|
|
346
|
+
id: "document",
|
|
347
|
+
label: "Reference a document",
|
|
348
|
+
picker: {
|
|
349
|
+
searchPlaceholder: "Search documents",
|
|
350
|
+
items: [{ id: "brief", title: "Project brief" }],
|
|
351
|
+
onSelect,
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
id: "notes",
|
|
356
|
+
label: "Document notes",
|
|
357
|
+
onSelect() {},
|
|
358
|
+
render: () => <div>Notes page</div>,
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
includeDefaultMentionSearch: false,
|
|
117
364
|
});
|
|
118
365
|
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
366
|
+
await act(async () => editor.focus());
|
|
367
|
+
|
|
368
|
+
await typeInto(editor, "@doc");
|
|
369
|
+
const rows = Array.from(
|
|
370
|
+
document.querySelectorAll("[data-mention-index]"),
|
|
371
|
+
(row) => row.textContent,
|
|
372
|
+
);
|
|
373
|
+
// Custom pages render only inside the + menu.
|
|
374
|
+
expect(rows).toEqual(["Reference a document"]);
|
|
375
|
+
await pressEnter(editor);
|
|
119
376
|
|
|
377
|
+
const dialog = document.querySelector('[role="dialog"]')!;
|
|
378
|
+
expect(dialog.textContent).toContain("Reference a document");
|
|
379
|
+
expect(editor.textContent).toBe("");
|
|
380
|
+
const option = dialog.querySelector<HTMLButtonElement>(
|
|
381
|
+
'[role="radio"][value="brief"]',
|
|
382
|
+
)!;
|
|
383
|
+
await act(async () => {
|
|
384
|
+
option.click();
|
|
385
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
386
|
+
});
|
|
387
|
+
expect(onSelect).toHaveBeenCalledWith(
|
|
388
|
+
expect.objectContaining({ id: "brief" }),
|
|
389
|
+
expect.anything(),
|
|
390
|
+
);
|
|
391
|
+
});
|
|
392
|
+
it("dismisses @ suggestions with one Escape and keeps typing as text", async () => {
|
|
393
|
+
const { onSubmit } = await mount({
|
|
394
|
+
initialText: "",
|
|
395
|
+
contextMenuItems: [
|
|
396
|
+
{ id: "source", label: "Choose source", onSelect() {} },
|
|
397
|
+
],
|
|
398
|
+
includeDefaultMentionSearch: false,
|
|
399
|
+
mentionItems: [slidesAgent],
|
|
400
|
+
});
|
|
401
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
402
|
+
await act(async () => editor.focus());
|
|
403
|
+
|
|
404
|
+
await typeInto(editor, "Ask @Sli");
|
|
120
405
|
await act(async () => {
|
|
121
|
-
editor.focus();
|
|
122
406
|
editor.dispatchEvent(
|
|
123
407
|
new KeyboardEvent("keydown", {
|
|
124
|
-
key: "
|
|
408
|
+
key: "Escape",
|
|
125
409
|
bubbles: true,
|
|
126
410
|
cancelable: true,
|
|
127
411
|
}),
|
|
128
412
|
);
|
|
129
413
|
});
|
|
414
|
+
expect(
|
|
415
|
+
document.querySelector('[data-agent-native-mention-popover="true"]'),
|
|
416
|
+
).toBeNull();
|
|
417
|
+
await typeInto(editor, "des rock");
|
|
130
418
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
expect(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
419
|
+
expect(
|
|
420
|
+
document.querySelector('[data-agent-native-mention-popover="true"]'),
|
|
421
|
+
).toBeNull();
|
|
422
|
+
expect(editor.textContent).toBe("Ask @Slides rock");
|
|
423
|
+
await pressEnter(editor);
|
|
424
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Ask @Slides rock");
|
|
425
|
+
});
|
|
426
|
+
it("keeps every key typed while a slow mention search is pending", async () => {
|
|
427
|
+
const pending: Array<() => void> = [];
|
|
428
|
+
vi.stubGlobal(
|
|
429
|
+
"fetch",
|
|
430
|
+
vi.fn(
|
|
431
|
+
() =>
|
|
432
|
+
new Promise<Response>((resolve) =>
|
|
433
|
+
pending.push(() =>
|
|
434
|
+
resolve(new Response('{"items":[]}\n', { status: 200 })),
|
|
435
|
+
),
|
|
436
|
+
),
|
|
437
|
+
),
|
|
438
|
+
);
|
|
439
|
+
const { onSubmit } = await mount({ initialText: "" });
|
|
440
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
441
|
+
await act(async () => editor.focus());
|
|
442
|
+
|
|
443
|
+
await typeInto(editor, "Ping a @builder.io email");
|
|
444
|
+
await act(async () => new Promise((resolve) => setTimeout(resolve, 250)));
|
|
445
|
+
expect(editor.textContent).toBe("Ping a @builder.io email");
|
|
446
|
+
expect(document.activeElement).toBe(editor);
|
|
447
|
+
|
|
448
|
+
await act(async () => {
|
|
449
|
+
pending.splice(0).forEach((release) => release());
|
|
450
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
451
|
+
});
|
|
452
|
+
expect(
|
|
453
|
+
document.querySelector('[data-agent-native-mention-popover="true"]'),
|
|
454
|
+
).toBeNull();
|
|
455
|
+
await pressEnter(editor);
|
|
456
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Ping a @builder.io email");
|
|
457
|
+
});
|
|
458
|
+
it("sends a typed @ on Enter while its search is pending, ignoring a late match", async () => {
|
|
459
|
+
const pending: Array<() => void> = [];
|
|
460
|
+
vi.stubGlobal(
|
|
461
|
+
"fetch",
|
|
462
|
+
vi.fn(
|
|
463
|
+
() =>
|
|
464
|
+
new Promise<Response>((resolve) =>
|
|
465
|
+
pending.push(() =>
|
|
466
|
+
resolve(
|
|
467
|
+
new Response(
|
|
468
|
+
JSON.stringify({
|
|
469
|
+
items: [{ ...slidesAgent, label: "Alice" }],
|
|
470
|
+
}) + "\n",
|
|
471
|
+
{ status: 200 },
|
|
472
|
+
),
|
|
473
|
+
),
|
|
474
|
+
),
|
|
475
|
+
),
|
|
476
|
+
),
|
|
477
|
+
);
|
|
478
|
+
const onReferencesChange = vi.fn();
|
|
479
|
+
const { onSubmit } = await mount({ initialText: "", onReferencesChange });
|
|
480
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
481
|
+
await act(async () => editor.focus());
|
|
159
482
|
|
|
483
|
+
await typeInto(editor, "Ask @Ali");
|
|
484
|
+
await pressEnter(editor);
|
|
485
|
+
expect(onSubmit).toHaveBeenCalledOnce();
|
|
486
|
+
expect(onSubmit.mock.calls[0]![0]).toBe("Ask @Ali");
|
|
487
|
+
|
|
488
|
+
await act(async () => {
|
|
489
|
+
pending.splice(0).forEach((release) => release());
|
|
490
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
491
|
+
});
|
|
492
|
+
expect(onSubmit).toHaveBeenCalledOnce();
|
|
493
|
+
expect(onReferencesChange).not.toHaveBeenCalledWith([
|
|
494
|
+
expect.objectContaining({ refId: "slides" }),
|
|
495
|
+
]);
|
|
496
|
+
});
|
|
497
|
+
it("opens the shared Add menu from + without inserting a mention", async () => {
|
|
498
|
+
const onSelect = vi.fn();
|
|
499
|
+
await mount({
|
|
500
|
+
initialText: "",
|
|
501
|
+
contextMenuItems: [{ id: "source", label: "Choose source", onSelect }],
|
|
502
|
+
});
|
|
503
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
160
504
|
const plusButton = container.querySelector<HTMLButtonElement>(
|
|
161
505
|
'button[aria-label="Add context"]',
|
|
162
506
|
)!;
|
|
163
|
-
await act(async () =>
|
|
164
|
-
Array.from(document.querySelectorAll<HTMLElement>('[role^="menuitem"]'))
|
|
165
|
-
.find((item) => item.textContent === "Choose source")!
|
|
166
|
-
.dispatchEvent(
|
|
167
|
-
new KeyboardEvent("keydown", {
|
|
168
|
-
key: "Escape",
|
|
169
|
-
bubbles: true,
|
|
170
|
-
cancelable: true,
|
|
171
|
-
}),
|
|
172
|
-
),
|
|
173
|
-
);
|
|
174
|
-
await act(async () =>
|
|
175
|
-
document.dispatchEvent(
|
|
176
|
-
new KeyboardEvent("keydown", { key: "Escape", bubbles: true }),
|
|
177
|
-
),
|
|
178
|
-
);
|
|
179
|
-
expect(document.querySelector('[role="menu"]')).toBeNull();
|
|
180
507
|
await act(async () =>
|
|
181
508
|
plusButton.dispatchEvent(
|
|
182
509
|
new KeyboardEvent("keydown", {
|
|
@@ -188,51 +515,133 @@ describe("controlled composer context", () => {
|
|
|
188
515
|
);
|
|
189
516
|
|
|
190
517
|
const plusMenu = document.querySelector<HTMLElement>('[role="menu"]');
|
|
518
|
+
expect(plusMenu?.textContent).toContain("Upload File");
|
|
191
519
|
expect(plusMenu?.textContent).toContain("Add context");
|
|
192
|
-
|
|
193
|
-
|
|
520
|
+
expect(plusMenu?.textContent).not.toContain("Choose source");
|
|
521
|
+
const addContext = Array.from(
|
|
522
|
+
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
523
|
+
).find((item) => item.textContent === "Add context")!;
|
|
524
|
+
await act(async () => {
|
|
525
|
+
addContext.focus();
|
|
526
|
+
addContext.dispatchEvent(
|
|
527
|
+
new KeyboardEvent("keydown", {
|
|
528
|
+
key: "ArrowRight",
|
|
529
|
+
bubbles: true,
|
|
530
|
+
cancelable: true,
|
|
531
|
+
}),
|
|
532
|
+
);
|
|
533
|
+
});
|
|
194
534
|
const sourceAction = Array.from(
|
|
195
535
|
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
196
536
|
).find((item) => item.textContent === "Choose source")!;
|
|
197
537
|
await act(async () => sourceAction.click());
|
|
198
538
|
expect(onSelect).toHaveBeenCalledOnce();
|
|
539
|
+
expect(editor.textContent).toBe("");
|
|
199
540
|
});
|
|
200
|
-
it
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
items: [{ id: "github", title: "GitHub" }],
|
|
213
|
-
onSelect,
|
|
214
|
-
},
|
|
541
|
+
it("opens the integration submenu from + without changing the draft", async () => {
|
|
542
|
+
const onSelect = vi.fn();
|
|
543
|
+
await mount({
|
|
544
|
+
initialText: "Keep my draft ",
|
|
545
|
+
contextMenuItems: [
|
|
546
|
+
{
|
|
547
|
+
id: "integrations",
|
|
548
|
+
label: "Integrations",
|
|
549
|
+
picker: {
|
|
550
|
+
searchPlaceholder: "Search integrations",
|
|
551
|
+
items: [{ id: "github", title: "GitHub" }],
|
|
552
|
+
onSelect,
|
|
215
553
|
},
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
});
|
|
557
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
558
|
+
const button = container.querySelector<HTMLButtonElement>(
|
|
559
|
+
'button[aria-label="Add context"]',
|
|
560
|
+
)!;
|
|
561
|
+
await act(async () => {
|
|
562
|
+
button.focus();
|
|
563
|
+
button.dispatchEvent(
|
|
564
|
+
new KeyboardEvent("keydown", {
|
|
565
|
+
key: "ArrowDown",
|
|
566
|
+
bubbles: true,
|
|
567
|
+
cancelable: true,
|
|
568
|
+
}),
|
|
569
|
+
);
|
|
570
|
+
});
|
|
571
|
+
const addContext = Array.from(
|
|
572
|
+
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
573
|
+
).find((item) => item.textContent === "Add context")!;
|
|
574
|
+
await act(async () => {
|
|
575
|
+
addContext.focus();
|
|
576
|
+
addContext.dispatchEvent(
|
|
577
|
+
new KeyboardEvent("keydown", {
|
|
578
|
+
key: "ArrowRight",
|
|
579
|
+
bubbles: true,
|
|
580
|
+
cancelable: true,
|
|
581
|
+
}),
|
|
582
|
+
);
|
|
583
|
+
});
|
|
584
|
+
const integrations = Array.from(
|
|
585
|
+
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
586
|
+
).find((item) => item.textContent === "Integrations")!;
|
|
587
|
+
expect(integrations.textContent).toBe("Integrations");
|
|
588
|
+
await act(async () => {
|
|
589
|
+
integrations.focus();
|
|
590
|
+
integrations.dispatchEvent(
|
|
591
|
+
new KeyboardEvent("keydown", {
|
|
592
|
+
key: "ArrowRight",
|
|
593
|
+
bubbles: true,
|
|
594
|
+
cancelable: true,
|
|
595
|
+
}),
|
|
596
|
+
);
|
|
597
|
+
});
|
|
598
|
+
const github = document.querySelector<HTMLElement>(
|
|
599
|
+
'[role="menuitemcheckbox"]',
|
|
600
|
+
)!;
|
|
601
|
+
expect(github.textContent).toBe("GitHub");
|
|
602
|
+
await act(async () => github.click());
|
|
603
|
+
expect(onSelect).toHaveBeenCalledOnce();
|
|
604
|
+
expect(editor.textContent).toBe("Keep my draft ");
|
|
605
|
+
expect(document.querySelector('[role="menu"]')).toBeNull();
|
|
606
|
+
});
|
|
607
|
+
it("adds discovered references from + and restores draft focus without submitting", async () => {
|
|
608
|
+
const onReferencesChange = vi.fn();
|
|
609
|
+
const { onSubmit } = await mount({
|
|
610
|
+
initialText: "My draft ",
|
|
611
|
+
contextMenuItems: [],
|
|
612
|
+
includeDefaultMentionSearch: false,
|
|
613
|
+
onReferencesChange,
|
|
614
|
+
mentionItems: [
|
|
615
|
+
{
|
|
616
|
+
id: "agent:slides",
|
|
617
|
+
label: "Slides",
|
|
618
|
+
description: "Presentations in this workspace",
|
|
619
|
+
section: "Connected Agents",
|
|
620
|
+
source: "agent",
|
|
621
|
+
refType: "agent",
|
|
622
|
+
refId: "slides",
|
|
623
|
+
refPath: "https://slides.example.test",
|
|
624
|
+
},
|
|
625
|
+
],
|
|
626
|
+
});
|
|
627
|
+
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
628
|
+
const target = container.querySelector<HTMLButtonElement>(
|
|
629
|
+
'button[aria-label="Add context"]',
|
|
630
|
+
)!;
|
|
631
|
+
await act(async () => {
|
|
632
|
+
target.focus();
|
|
633
|
+
target.dispatchEvent(
|
|
634
|
+
new KeyboardEvent("keydown", {
|
|
635
|
+
key: "ArrowDown",
|
|
636
|
+
bubbles: true,
|
|
637
|
+
cancelable: true,
|
|
638
|
+
}),
|
|
639
|
+
);
|
|
640
|
+
});
|
|
641
|
+
const addContext = Array.from(
|
|
642
|
+
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
643
|
+
).find((item) => item.textContent === "Add context");
|
|
644
|
+
if (addContext) {
|
|
236
645
|
await act(async () => {
|
|
237
646
|
addContext.focus();
|
|
238
647
|
addContext.dispatchEvent(
|
|
@@ -243,13 +652,14 @@ describe("controlled composer context", () => {
|
|
|
243
652
|
}),
|
|
244
653
|
);
|
|
245
654
|
});
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
655
|
+
}
|
|
656
|
+
const section = Array.from(
|
|
657
|
+
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
658
|
+
).find((item) => item.textContent === "Connected Agents");
|
|
659
|
+
if (section) {
|
|
250
660
|
await act(async () => {
|
|
251
|
-
|
|
252
|
-
|
|
661
|
+
section.focus();
|
|
662
|
+
section.dispatchEvent(
|
|
253
663
|
new KeyboardEvent("keydown", {
|
|
254
664
|
key: "ArrowRight",
|
|
255
665
|
bubbles: true,
|
|
@@ -257,109 +667,30 @@ describe("controlled composer context", () => {
|
|
|
257
667
|
}),
|
|
258
668
|
);
|
|
259
669
|
});
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
"
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
section: "Connected Agents",
|
|
285
|
-
source: "agent",
|
|
286
|
-
refType: "agent",
|
|
287
|
-
refId: "slides",
|
|
288
|
-
refPath: "https://slides.example.test",
|
|
289
|
-
},
|
|
290
|
-
],
|
|
291
|
-
});
|
|
292
|
-
const editor = container.querySelector<HTMLElement>(".ProseMirror")!;
|
|
293
|
-
const target =
|
|
294
|
-
trigger === "@"
|
|
295
|
-
? editor
|
|
296
|
-
: container.querySelector<HTMLButtonElement>(
|
|
297
|
-
'button[aria-label="Add context"]',
|
|
298
|
-
)!;
|
|
299
|
-
await act(async () => {
|
|
300
|
-
target.focus();
|
|
301
|
-
target.dispatchEvent(
|
|
302
|
-
new KeyboardEvent("keydown", {
|
|
303
|
-
key: trigger === "@" ? "@" : "ArrowDown",
|
|
304
|
-
bubbles: true,
|
|
305
|
-
cancelable: true,
|
|
306
|
-
}),
|
|
307
|
-
);
|
|
308
|
-
});
|
|
309
|
-
const addContext = Array.from(
|
|
310
|
-
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
311
|
-
).find((item) => item.textContent === "Add context");
|
|
312
|
-
if (addContext) {
|
|
313
|
-
await act(async () => {
|
|
314
|
-
addContext.focus();
|
|
315
|
-
addContext.dispatchEvent(
|
|
316
|
-
new KeyboardEvent("keydown", {
|
|
317
|
-
key: "ArrowRight",
|
|
318
|
-
bubbles: true,
|
|
319
|
-
cancelable: true,
|
|
320
|
-
}),
|
|
321
|
-
);
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
const section = Array.from(
|
|
325
|
-
document.querySelectorAll<HTMLElement>('[role^="menuitem"]'),
|
|
326
|
-
).find((item) => item.textContent === "Connected Agents");
|
|
327
|
-
if (section) {
|
|
328
|
-
await act(async () => {
|
|
329
|
-
section.focus();
|
|
330
|
-
section.dispatchEvent(
|
|
331
|
-
new KeyboardEvent("keydown", {
|
|
332
|
-
key: "ArrowRight",
|
|
333
|
-
bubbles: true,
|
|
334
|
-
cancelable: true,
|
|
335
|
-
}),
|
|
336
|
-
);
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
const row = Array.from(
|
|
340
|
-
document.querySelectorAll<HTMLElement>('[role="menuitem"]'),
|
|
341
|
-
).find(
|
|
342
|
-
(item) => item.textContent === "SlidesPresentations in this workspace",
|
|
343
|
-
)!;
|
|
344
|
-
expect(row).toBeDefined();
|
|
345
|
-
await act(async () => row.click());
|
|
346
|
-
await act(async () => {
|
|
347
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
348
|
-
});
|
|
349
|
-
expect(editor.textContent).toContain("My draft");
|
|
350
|
-
expect(editor.textContent).toContain("Slides");
|
|
351
|
-
expect(editor.textContent).not.toContain("@");
|
|
352
|
-
expect(onReferencesChange).toHaveBeenLastCalledWith([
|
|
353
|
-
expect.objectContaining({
|
|
354
|
-
refType: "agent",
|
|
355
|
-
refId: "slides",
|
|
356
|
-
path: "https://slides.example.test",
|
|
357
|
-
}),
|
|
358
|
-
]);
|
|
359
|
-
expect(document.activeElement).toBe(editor);
|
|
360
|
-
expect(onSubmit).not.toHaveBeenCalled();
|
|
361
|
-
},
|
|
362
|
-
);
|
|
670
|
+
}
|
|
671
|
+
const row = Array.from(
|
|
672
|
+
document.querySelectorAll<HTMLElement>('[role="menuitem"]'),
|
|
673
|
+
).find(
|
|
674
|
+
(item) => item.textContent === "SlidesPresentations in this workspace",
|
|
675
|
+
)!;
|
|
676
|
+
expect(row).toBeDefined();
|
|
677
|
+
await act(async () => row.click());
|
|
678
|
+
await act(async () => {
|
|
679
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
680
|
+
});
|
|
681
|
+
expect(editor.textContent).toContain("My draft");
|
|
682
|
+
expect(editor.textContent).toContain("Slides");
|
|
683
|
+
expect(editor.textContent).not.toContain("@");
|
|
684
|
+
expect(onReferencesChange).toHaveBeenLastCalledWith([
|
|
685
|
+
expect.objectContaining({
|
|
686
|
+
refType: "agent",
|
|
687
|
+
refId: "slides",
|
|
688
|
+
path: "https://slides.example.test",
|
|
689
|
+
}),
|
|
690
|
+
]);
|
|
691
|
+
expect(document.activeElement).toBe(editor);
|
|
692
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
693
|
+
});
|
|
363
694
|
it("keeps regular @ references when the shared Add menu is explicitly hidden", async () => {
|
|
364
695
|
await mount({
|
|
365
696
|
plusMenuMode: "hidden",
|