mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-10 22:32:16 +02:00
feat(rename): complete searchSpace to workspace transition across frontend and backend
- Introduced a comprehensive specification for renaming `searchSpace` to `workspace` in `surfsense_web` and `surfsense_desktop`, ensuring all TypeScript identifiers, React props, and local data structures are updated. - Implemented migration shims for persisted local state to prevent data loss during the transition. - Updated observability metrics and IPC channels to reflect the new naming convention. - Removed legacy `active-search-space` module and replaced it with `active-workspace` to maintain consistency. - Ensured no behavioral changes or data loss for users during the renaming process.
This commit is contained in:
parent
2a020629c5
commit
a8c1fb660d
259 changed files with 5480 additions and 2285 deletions
|
|
@ -16,7 +16,7 @@ test.describe("ClickUp connector journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
clickupConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -40,7 +40,7 @@ test.describe("ClickUp connector journey", () => {
|
|||
expect(clickupConnector.config.access_token).toBeUndefined();
|
||||
expect(clickupConnector.config.refresh_token).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -48,20 +48,20 @@ test.describe("ClickUp connector journey", () => {
|
|||
await expect(connectorDialog).toBeVisible();
|
||||
await expect(connectorDialog.getByText("ClickUp")).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
clickupConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my ClickUp task titled "${FAKE_CLICKUP_TASKS.canary.name}"?`,
|
||||
});
|
||||
|
|
@ -73,13 +73,13 @@ test.describe("ClickUp connector journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("clickup_search");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === clickupConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("CLICKUP_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,24 +17,24 @@ test.describe("Composio Calendar journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
composioCalendarConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
test.setTimeout(90_000); // worker cold-start + live tool chat
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
const connectorDialog = page.getByRole("dialog", { name: "Manage Connectors" });
|
||||
await expect(connectorDialog).toBeVisible();
|
||||
|
||||
const beforeChatDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeChatDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeChatDocs).toHaveLength(0);
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query:
|
||||
`What Calendar event mentions ${CANARY_TOKENS.calendarCanary} next week? ` +
|
||||
|
|
@ -48,11 +48,11 @@ test.describe("Composio Calendar journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("search_calendar_events");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === composioCalendarConnector.id);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterChatDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterChatDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterChatDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ test.describe("Composio Drive journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
composioDriveConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
test.setTimeout(240_000); // worker cold-start + Docling + summarize + embed + chunk
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -60,29 +60,29 @@ test.describe("Composio Drive journey", () => {
|
|||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await triggerIndex(request, apiToken, composioDriveConnector.id, searchSpace.id, {
|
||||
await triggerIndex(request, apiToken, composioDriveConnector.id, workspace.id, {
|
||||
files: selectedFiles,
|
||||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await waitForIndexingComplete(request, apiToken, composioDriveConnector.id, searchSpace.id, {
|
||||
await waitForIndexingComplete(request, apiToken, composioDriveConnector.id, workspace.id, {
|
||||
timeoutMs: 240_000,
|
||||
intervalMs: 1_500,
|
||||
minDocuments: 2,
|
||||
});
|
||||
|
||||
await waitForDocumentByTitle(request, apiToken, searchSpace.id, FAKE_DRIVE_FILES.canary.name, {
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_DRIVE_FILES.canary.name, {
|
||||
timeoutMs: 30_000,
|
||||
});
|
||||
await waitForDocumentByTitle(
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace.id,
|
||||
workspace.id,
|
||||
FAKE_DRIVE_FILES.pdfComposio.name,
|
||||
{ timeoutMs: 60_000 }
|
||||
);
|
||||
|
||||
const docs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const docs = await listDocuments(request, apiToken, workspace.id);
|
||||
const canaryDoc = docs.find((d) => d.title === FAKE_DRIVE_FILES.canary.name);
|
||||
const pdfDoc = docs.find((d) => d.title === FAKE_DRIVE_FILES.pdfComposio.name);
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ test.describe("Composio Drive journey", () => {
|
|||
|
||||
// content holds the LLM summary; the raw file body lives in source_markdown.
|
||||
// editor-content is the same endpoint the UI hits when opening a document.
|
||||
const editor = await getEditorContent(request, apiToken, searchSpace.id, canaryDoc.id);
|
||||
const editor = await getEditorContent(request, apiToken, workspace.id, canaryDoc.id);
|
||||
expect(
|
||||
editor.source_markdown,
|
||||
`canary token ${CANARY_TOKENS.driveCanaryFile} should appear in editor source_markdown; ` +
|
||||
|
|
@ -104,7 +104,7 @@ test.describe("Composio Drive journey", () => {
|
|||
expect(editor.document_type).toBe("GOOGLE_DRIVE_FILE");
|
||||
expect(editor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const pdfEditor = await getEditorContent(request, apiToken, searchSpace.id, pdfDoc.id);
|
||||
const pdfEditor = await getEditorContent(request, apiToken, workspace.id, pdfDoc.id);
|
||||
expect(
|
||||
pdfEditor.source_markdown,
|
||||
`PDF canary token ${CANARY_TOKENS.composioDrivePdfCanary} should appear in editor source_markdown; ` +
|
||||
|
|
@ -113,12 +113,12 @@ test.describe("Composio Drive journey", () => {
|
|||
expect(pdfEditor.document_type).toBe("GOOGLE_DRIVE_FILE");
|
||||
expect(pdfEditor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === composioDriveConnector.id);
|
||||
expect(refreshed?.last_indexed_at).not.toBeNull();
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-canary.txt Drive file?",
|
||||
});
|
||||
|
|
@ -128,7 +128,7 @@ test.describe("Composio Drive journey", () => {
|
|||
).toContain(CANARY_TOKENS.driveCanaryFile);
|
||||
|
||||
const pdfChat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-composio-canary.pdf Drive file?",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,24 +17,24 @@ test.describe("Composio Gmail journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
composioGmailConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
test.setTimeout(90_000); // worker cold-start + live tool chat
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
const connectorDialog = page.getByRole("dialog", { name: "Manage Connectors" });
|
||||
await expect(connectorDialog).toBeVisible();
|
||||
|
||||
const beforeChatDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeChatDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeChatDocs).toHaveLength(0);
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Gmail message titled "${FAKE_GMAIL_MESSAGES.canary.subject}"?`,
|
||||
});
|
||||
|
|
@ -47,11 +47,11 @@ test.describe("Composio Gmail journey", () => {
|
|||
expect(eventText).toContain("search_gmail");
|
||||
expect(eventText).toContain("read_gmail_email");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === composioGmailConnector.id);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterChatDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterChatDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterChatDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.describe("Confluence connector journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
confluenceConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -44,7 +44,7 @@ test.describe("Confluence connector journey", () => {
|
|||
expect(confluenceConnector.config.access_token).toBeUndefined();
|
||||
expect(confluenceConnector.config.refresh_token).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -53,20 +53,20 @@ test.describe("Confluence connector journey", () => {
|
|||
await connectorDialog.getByPlaceholder("Search").fill("Confluence");
|
||||
await expect(connectorDialog.getByText("Confluence", { exact: true })).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
confluenceConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Confluence page titled "${FAKE_CONFLUENCE_PAGES.canary.title}"?`,
|
||||
});
|
||||
|
|
@ -78,13 +78,13 @@ test.describe("Confluence connector journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("searchConfluenceUsingCql");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === confluenceConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("CONFLUENCE_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.describe("Native Dropbox journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
nativeDropboxConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -29,7 +29,7 @@ test.describe("Native Dropbox journey", () => {
|
|||
expect(nativeDropboxConnector.config._token_encrypted).toBe(true);
|
||||
expect(nativeDropboxConnector.config.composio_connected_account_id).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -63,29 +63,25 @@ test.describe("Native Dropbox journey", () => {
|
|||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await triggerIndex(request, apiToken, nativeDropboxConnector.id, searchSpace.id, {
|
||||
await triggerIndex(request, apiToken, nativeDropboxConnector.id, workspace.id, {
|
||||
files: selectedFiles,
|
||||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await waitForIndexingComplete(request, apiToken, nativeDropboxConnector.id, searchSpace.id, {
|
||||
await waitForIndexingComplete(request, apiToken, nativeDropboxConnector.id, workspace.id, {
|
||||
timeoutMs: 240_000,
|
||||
intervalMs: 1_500,
|
||||
minDocuments: 2,
|
||||
});
|
||||
|
||||
await waitForDocumentByTitle(
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace.id,
|
||||
FAKE_DROPBOX_FILES.canary.name,
|
||||
{ timeoutMs: 30_000 }
|
||||
);
|
||||
await waitForDocumentByTitle(request, apiToken, searchSpace.id, FAKE_DROPBOX_FILES.pdf.name, {
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_DROPBOX_FILES.canary.name, {
|
||||
timeoutMs: 30_000,
|
||||
});
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_DROPBOX_FILES.pdf.name, {
|
||||
timeoutMs: 60_000,
|
||||
});
|
||||
|
||||
const docs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const docs = await listDocuments(request, apiToken, workspace.id);
|
||||
const canaryDoc = docs.find((d) => d.title === FAKE_DROPBOX_FILES.canary.name);
|
||||
const pdfDoc = docs.find((d) => d.title === FAKE_DROPBOX_FILES.pdf.name);
|
||||
|
||||
|
|
@ -96,7 +92,7 @@ test.describe("Native Dropbox journey", () => {
|
|||
if (!pdfDoc) throw new Error("unreachable: pdfDoc asserted defined above");
|
||||
expect(pdfDoc.document_type).toBe("DROPBOX_FILE");
|
||||
|
||||
const editor = await getEditorContent(request, apiToken, searchSpace.id, canaryDoc.id);
|
||||
const editor = await getEditorContent(request, apiToken, workspace.id, canaryDoc.id);
|
||||
expect(
|
||||
editor.source_markdown,
|
||||
`canary token ${CANARY_TOKENS.dropboxCanary} should appear in editor source_markdown; ` +
|
||||
|
|
@ -105,7 +101,7 @@ test.describe("Native Dropbox journey", () => {
|
|||
expect(editor.document_type).toBe("DROPBOX_FILE");
|
||||
expect(editor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const pdfEditor = await getEditorContent(request, apiToken, searchSpace.id, pdfDoc.id);
|
||||
const pdfEditor = await getEditorContent(request, apiToken, workspace.id, pdfDoc.id);
|
||||
expect(
|
||||
pdfEditor.source_markdown,
|
||||
`PDF canary token ${CANARY_TOKENS.dropboxPdfCanary} should appear in editor source_markdown; ` +
|
||||
|
|
@ -114,14 +110,14 @@ test.describe("Native Dropbox journey", () => {
|
|||
expect(pdfEditor.document_type).toBe("DROPBOX_FILE");
|
||||
expect(pdfEditor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === nativeDropboxConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("DROPBOX_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(true);
|
||||
expect(refreshed?.last_indexed_at).not.toBeNull();
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-dropbox-canary.txt Dropbox file?",
|
||||
});
|
||||
|
|
@ -132,7 +128,7 @@ test.describe("Native Dropbox journey", () => {
|
|||
).toContain(CANARY_TOKENS.dropboxCanary);
|
||||
|
||||
const pdfChat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-dropbox-canary.pdf Dropbox file?",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ test.describe("Native Google Calendar journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
nativeCalendarConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -28,27 +28,27 @@ test.describe("Native Google Calendar journey", () => {
|
|||
expect(nativeCalendarConnector.config._token_encrypted).toBe(true);
|
||||
expect(nativeCalendarConnector.config.composio_connected_account_id).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
const connectorDialog = page.getByRole("dialog", { name: "Manage Connectors" });
|
||||
await expect(connectorDialog).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
nativeCalendarConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query:
|
||||
`What Calendar event mentions ${CANARY_TOKENS.calendarCanary} next week? ` +
|
||||
|
|
@ -62,13 +62,13 @@ test.describe("Native Google Calendar journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("search_calendar_events");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === nativeCalendarConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("GOOGLE_CALENDAR_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ test.describe("Native Google Drive journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
nativeDriveConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -33,7 +33,7 @@ test.describe("Native Google Drive journey", () => {
|
|||
expect(nativeDriveConnector.config._token_encrypted).toBe(true);
|
||||
expect(nativeDriveConnector.config.composio_connected_account_id).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -65,29 +65,25 @@ test.describe("Native Google Drive journey", () => {
|
|||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await triggerIndex(request, apiToken, nativeDriveConnector.id, searchSpace.id, {
|
||||
await triggerIndex(request, apiToken, nativeDriveConnector.id, workspace.id, {
|
||||
files: selectedFiles,
|
||||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await waitForIndexingComplete(request, apiToken, nativeDriveConnector.id, searchSpace.id, {
|
||||
await waitForIndexingComplete(request, apiToken, nativeDriveConnector.id, workspace.id, {
|
||||
timeoutMs: 240_000,
|
||||
intervalMs: 1_500,
|
||||
minDocuments: 2,
|
||||
});
|
||||
|
||||
await waitForDocumentByTitle(request, apiToken, searchSpace.id, FAKE_DRIVE_FILES.canary.name, {
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_DRIVE_FILES.canary.name, {
|
||||
timeoutMs: 30_000,
|
||||
});
|
||||
await waitForDocumentByTitle(
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace.id,
|
||||
FAKE_DRIVE_FILES.pdfNative.name,
|
||||
{ timeoutMs: 60_000 }
|
||||
);
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_DRIVE_FILES.pdfNative.name, {
|
||||
timeoutMs: 60_000,
|
||||
});
|
||||
|
||||
const docs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const docs = await listDocuments(request, apiToken, workspace.id);
|
||||
const canaryDoc = docs.find((d) => d.title === FAKE_DRIVE_FILES.canary.name);
|
||||
const pdfDoc = docs.find((d) => d.title === FAKE_DRIVE_FILES.pdfNative.name);
|
||||
|
||||
|
|
@ -98,7 +94,7 @@ test.describe("Native Google Drive journey", () => {
|
|||
if (!pdfDoc) throw new Error("unreachable: pdfDoc asserted defined above");
|
||||
expect(pdfDoc.document_type).toBe("GOOGLE_DRIVE_FILE");
|
||||
|
||||
const editor = await getEditorContent(request, apiToken, searchSpace.id, canaryDoc.id);
|
||||
const editor = await getEditorContent(request, apiToken, workspace.id, canaryDoc.id);
|
||||
expect(
|
||||
editor.source_markdown,
|
||||
`canary token ${CANARY_TOKENS.driveCanaryFile} should appear in editor source_markdown; ` +
|
||||
|
|
@ -107,7 +103,7 @@ test.describe("Native Google Drive journey", () => {
|
|||
expect(editor.document_type).toBe("GOOGLE_DRIVE_FILE");
|
||||
expect(editor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const pdfEditor = await getEditorContent(request, apiToken, searchSpace.id, pdfDoc.id);
|
||||
const pdfEditor = await getEditorContent(request, apiToken, workspace.id, pdfDoc.id);
|
||||
expect(
|
||||
pdfEditor.source_markdown,
|
||||
`PDF canary token ${CANARY_TOKENS.drivePdfCanary} should appear in editor source_markdown; ` +
|
||||
|
|
@ -116,14 +112,14 @@ test.describe("Native Google Drive journey", () => {
|
|||
expect(pdfEditor.document_type).toBe("GOOGLE_DRIVE_FILE");
|
||||
expect(pdfEditor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === nativeDriveConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("GOOGLE_DRIVE_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(true);
|
||||
expect(refreshed?.last_indexed_at).not.toBeNull();
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-canary.txt native Drive file?",
|
||||
});
|
||||
|
|
@ -133,7 +129,7 @@ test.describe("Native Google Drive journey", () => {
|
|||
).toContain(CANARY_TOKENS.driveCanaryFile);
|
||||
|
||||
const pdfChat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-canary.pdf native Drive file?",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ test.describe("Native Google Gmail journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
nativeGmailConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -28,27 +28,27 @@ test.describe("Native Google Gmail journey", () => {
|
|||
expect(nativeGmailConnector.config._token_encrypted).toBe(true);
|
||||
expect(nativeGmailConnector.config.composio_connected_account_id).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
const connectorDialog = page.getByRole("dialog", { name: "Manage Connectors" });
|
||||
await expect(connectorDialog).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
nativeGmailConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Gmail message titled "${FAKE_GMAIL_MESSAGES.canary.subject}"?`,
|
||||
});
|
||||
|
|
@ -61,13 +61,13 @@ test.describe("Native Google Gmail journey", () => {
|
|||
expect(eventText).toContain("search_gmail");
|
||||
expect(eventText).toContain("read_gmail_email");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === nativeGmailConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("GOOGLE_GMAIL_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ test.describe("Jira connector journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
jiraConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -38,7 +38,7 @@ test.describe("Jira connector journey", () => {
|
|||
expect(jiraConnector.config.access_token).toBeUndefined();
|
||||
expect(jiraConnector.config.refresh_token).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -47,20 +47,20 @@ test.describe("Jira connector journey", () => {
|
|||
await connectorDialog.getByPlaceholder("Search").fill("Jira");
|
||||
await expect(connectorDialog.getByText("Jira", { exact: true })).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
jiraConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Jira issue titled "${FAKE_JIRA_ISSUES.canary.summary}"?`,
|
||||
});
|
||||
|
|
@ -72,13 +72,13 @@ test.describe("Jira connector journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("searchJiraIssuesUsingJql");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === jiraConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("JIRA_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ test.describe("Linear connector journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
linearConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -38,27 +38,27 @@ test.describe("Linear connector journey", () => {
|
|||
expect(linearConnector.config.access_token).toBeUndefined();
|
||||
expect(linearConnector.config.refresh_token).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
const connectorDialog = page.getByRole("dialog", { name: "Manage Connectors" });
|
||||
await expect(connectorDialog).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
linearConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Linear issue titled "${FAKE_LINEAR_ISSUES.canary.title}"?`,
|
||||
});
|
||||
|
|
@ -70,13 +70,13 @@ test.describe("Linear connector journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("list_issues");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === linearConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("LINEAR_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ test.describe("Notion connector journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
notionConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -35,13 +35,11 @@ test.describe("Notion connector journey", () => {
|
|||
client_id: "fake-notion-mcp-client-id",
|
||||
token_endpoint: "https://mcp.notion.com/token",
|
||||
});
|
||||
expect(
|
||||
(notionConnector.config.mcp_oauth as Record<string, unknown>).access_token
|
||||
).toBeTruthy();
|
||||
expect((notionConnector.config.mcp_oauth as Record<string, unknown>).access_token).toBeTruthy();
|
||||
expect(notionConnector.config.access_token).toBeUndefined();
|
||||
expect(notionConnector.config.refresh_token).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -50,20 +48,20 @@ test.describe("Notion connector journey", () => {
|
|||
await connectorDialog.getByPlaceholder("Search").fill("Notion");
|
||||
await expect(connectorDialog.getByText("Notion", { exact: true })).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
notionConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Notion page titled "${FAKE_NOTION_PAGES.canary.title}"?`,
|
||||
});
|
||||
|
|
@ -75,13 +73,13 @@ test.describe("Notion connector journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain(FAKE_NOTION_PAGES.canary.id);
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === notionConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("NOTION_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.describe("Native OneDrive journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
nativeOneDriveConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -29,7 +29,7 @@ test.describe("Native OneDrive journey", () => {
|
|||
expect(nativeOneDriveConnector.config._token_encrypted).toBe(true);
|
||||
expect(nativeOneDriveConnector.config.composio_connected_account_id).toBeUndefined();
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -63,29 +63,25 @@ test.describe("Native OneDrive journey", () => {
|
|||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await triggerIndex(request, apiToken, nativeOneDriveConnector.id, searchSpace.id, {
|
||||
await triggerIndex(request, apiToken, nativeOneDriveConnector.id, workspace.id, {
|
||||
files: selectedFiles,
|
||||
indexing_options: indexingOptions,
|
||||
});
|
||||
|
||||
await waitForIndexingComplete(request, apiToken, nativeOneDriveConnector.id, searchSpace.id, {
|
||||
await waitForIndexingComplete(request, apiToken, nativeOneDriveConnector.id, workspace.id, {
|
||||
timeoutMs: 240_000,
|
||||
intervalMs: 1_500,
|
||||
minDocuments: 2,
|
||||
});
|
||||
|
||||
await waitForDocumentByTitle(
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace.id,
|
||||
FAKE_ONEDRIVE_FILES.canary.name,
|
||||
{ timeoutMs: 30_000 }
|
||||
);
|
||||
await waitForDocumentByTitle(request, apiToken, searchSpace.id, FAKE_ONEDRIVE_FILES.pdf.name, {
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_ONEDRIVE_FILES.canary.name, {
|
||||
timeoutMs: 30_000,
|
||||
});
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, FAKE_ONEDRIVE_FILES.pdf.name, {
|
||||
timeoutMs: 60_000,
|
||||
});
|
||||
|
||||
const docs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const docs = await listDocuments(request, apiToken, workspace.id);
|
||||
const canaryDoc = docs.find((d) => d.title === FAKE_ONEDRIVE_FILES.canary.name);
|
||||
const pdfDoc = docs.find((d) => d.title === FAKE_ONEDRIVE_FILES.pdf.name);
|
||||
|
||||
|
|
@ -96,7 +92,7 @@ test.describe("Native OneDrive journey", () => {
|
|||
if (!pdfDoc) throw new Error("unreachable: pdfDoc asserted defined above");
|
||||
expect(pdfDoc.document_type).toBe("ONEDRIVE_FILE");
|
||||
|
||||
const editor = await getEditorContent(request, apiToken, searchSpace.id, canaryDoc.id);
|
||||
const editor = await getEditorContent(request, apiToken, workspace.id, canaryDoc.id);
|
||||
expect(
|
||||
editor.source_markdown,
|
||||
`canary token ${CANARY_TOKENS.onedriveCanary} should appear in editor source_markdown; ` +
|
||||
|
|
@ -105,7 +101,7 @@ test.describe("Native OneDrive journey", () => {
|
|||
expect(editor.document_type).toBe("ONEDRIVE_FILE");
|
||||
expect(editor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const pdfEditor = await getEditorContent(request, apiToken, searchSpace.id, pdfDoc.id);
|
||||
const pdfEditor = await getEditorContent(request, apiToken, workspace.id, pdfDoc.id);
|
||||
expect(
|
||||
pdfEditor.source_markdown,
|
||||
`PDF canary token ${CANARY_TOKENS.onedrivePdfCanary} should appear in editor source_markdown; ` +
|
||||
|
|
@ -114,14 +110,14 @@ test.describe("Native OneDrive journey", () => {
|
|||
expect(pdfEditor.document_type).toBe("ONEDRIVE_FILE");
|
||||
expect(pdfEditor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === nativeOneDriveConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("ONEDRIVE_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(true);
|
||||
expect(refreshed?.last_indexed_at).not.toBeNull();
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-onedrive-canary.txt OneDrive file?",
|
||||
});
|
||||
|
|
@ -132,7 +128,7 @@ test.describe("Native OneDrive journey", () => {
|
|||
).toContain(CANARY_TOKENS.onedriveCanary);
|
||||
|
||||
const pdfChat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: "What is in my e2e-onedrive-canary.pdf OneDrive file?",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ test.describe("Slack connector journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
slackConnector,
|
||||
chatThread,
|
||||
}) => {
|
||||
|
|
@ -40,7 +40,7 @@ test.describe("Slack connector journey", () => {
|
|||
expect(slackConnector.config.team_id).toBe(FAKE_SLACK_CHANNELS.canary.teamId);
|
||||
expect(slackConnector.config.team_name).toBe(FAKE_SLACK_CHANNELS.canary.teamName);
|
||||
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await openConnectorPopup(page);
|
||||
|
|
@ -49,20 +49,20 @@ test.describe("Slack connector journey", () => {
|
|||
await connectorDialog.getByPlaceholder("Search").fill("Slack");
|
||||
await expect(connectorDialog.getByText("Slack", { exact: true })).toBeVisible();
|
||||
|
||||
const beforeDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const beforeDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(beforeDocs).toHaveLength(0);
|
||||
|
||||
const disabledIndex = await triggerIndexExpectDisabled(
|
||||
request,
|
||||
apiToken,
|
||||
slackConnector.id,
|
||||
searchSpace.id
|
||||
workspace.id
|
||||
);
|
||||
expect(disabledIndex.message ?? "").toContain("real-time agent tools");
|
||||
expect(disabledIndex.message ?? "").toContain("background indexing is disabled");
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: `What is in my Slack channel "${FAKE_SLACK_CHANNELS.canary.name}"?`,
|
||||
});
|
||||
|
|
@ -74,13 +74,13 @@ test.describe("Slack connector journey", () => {
|
|||
const eventText = JSON.stringify(chat.events);
|
||||
expect(eventText).toContain("slack_search_channels");
|
||||
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, searchSpace.id);
|
||||
const refreshedConnectors = await listConnectors(request, apiToken, workspace.id);
|
||||
const refreshed = refreshedConnectors.find((c) => c.id === slackConnector.id);
|
||||
expect(refreshed?.connector_type).toBe("SLACK_CONNECTOR");
|
||||
expect(refreshed?.is_indexable).toBe(false);
|
||||
expect(refreshed?.last_indexed_at).toBeNull();
|
||||
|
||||
const afterDocs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const afterDocs = await listDocuments(request, apiToken, workspace.id);
|
||||
expect(afterDocs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ type UploadFixture = {
|
|||
chatQuery: string;
|
||||
};
|
||||
|
||||
type SearchSpace = {
|
||||
type Workspace = {
|
||||
id: number;
|
||||
};
|
||||
|
||||
|
|
@ -36,18 +36,18 @@ async function uploadAndAssert({
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
chatThread,
|
||||
file,
|
||||
}: {
|
||||
page: Page;
|
||||
request: APIRequestContext;
|
||||
apiToken: string;
|
||||
searchSpace: SearchSpace;
|
||||
workspace: Workspace;
|
||||
chatThread: ChatThreadRow;
|
||||
file: UploadFixture;
|
||||
}) {
|
||||
await page.goto(`/dashboard/${searchSpace.id}/new-chat`, {
|
||||
await page.goto(`/dashboard/${workspace.id}/new-chat`, {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
|
||||
|
|
@ -62,22 +62,22 @@ async function uploadAndAssert({
|
|||
timeout: 15_000,
|
||||
});
|
||||
|
||||
await waitForDocumentByTitle(request, apiToken, searchSpace.id, file.name, {
|
||||
await waitForDocumentByTitle(request, apiToken, workspace.id, file.name, {
|
||||
timeoutMs: 200_000,
|
||||
});
|
||||
|
||||
const docs = await listDocuments(request, apiToken, searchSpace.id);
|
||||
const docs = await listDocuments(request, apiToken, workspace.id);
|
||||
const uploaded = docs.find((d) => d.title === file.name);
|
||||
expect(uploaded, `${file.name} must exist after indexing`).toBeDefined();
|
||||
if (!uploaded) throw new Error("unreachable: uploaded asserted defined above");
|
||||
expect(uploaded.document_type).toBe("FILE");
|
||||
|
||||
const editor = await getEditorContent(request, apiToken, searchSpace.id, uploaded.id);
|
||||
const editor = await getEditorContent(request, apiToken, workspace.id, uploaded.id);
|
||||
expect(editor.source_markdown).toContain(file.canary);
|
||||
expect(editor.chunk_count).toBeGreaterThan(0);
|
||||
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: chatThread.id,
|
||||
query: file.chatQuery,
|
||||
});
|
||||
|
|
@ -92,7 +92,7 @@ test.describe("Manual file upload journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
chatThread,
|
||||
}) => {
|
||||
test.setTimeout(180_000);
|
||||
|
|
@ -101,7 +101,7 @@ test.describe("Manual file upload journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
chatThread,
|
||||
file: MD_FILE,
|
||||
});
|
||||
|
|
@ -111,7 +111,7 @@ test.describe("Manual file upload journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
chatThread,
|
||||
}) => {
|
||||
test.setTimeout(180_000);
|
||||
|
|
@ -120,7 +120,7 @@ test.describe("Manual file upload journey", () => {
|
|||
page,
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
workspace,
|
||||
chatThread,
|
||||
file: PDF_FILE,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { APIRequestContext } from "@playwright/test";
|
||||
import { authHeaders, BACKEND_URL } from "../helpers/api/auth";
|
||||
import type { SearchSpaceFixtures } from "./workspace.fixture";
|
||||
import type { WorkspaceFixtures } from "./workspace.fixture";
|
||||
|
||||
export type ChatThreadRow = {
|
||||
id: number;
|
||||
|
|
@ -16,20 +16,20 @@ export type ChatThreadFixtures = {
|
|||
chatThread: ChatThreadRow;
|
||||
};
|
||||
|
||||
type ChatThreadFixtureArgs = SearchSpaceFixtures & {
|
||||
type ChatThreadFixtureArgs = WorkspaceFixtures & {
|
||||
request: APIRequestContext;
|
||||
};
|
||||
|
||||
export const chatThreadFixtures = {
|
||||
chatThread: async (
|
||||
{ request, apiToken, searchSpace }: ChatThreadFixtureArgs,
|
||||
{ request, apiToken, workspace }: ChatThreadFixtureArgs,
|
||||
use: (thread: ChatThreadRow) => Promise<void>
|
||||
) => {
|
||||
const response = await request.post(`${BACKEND_URL}/api/v1/threads`, {
|
||||
headers: authHeaders(apiToken),
|
||||
data: {
|
||||
title: "e2e-drive-journey",
|
||||
workspace_id: searchSpace.id,
|
||||
workspace_id: workspace.id,
|
||||
visibility: "PRIVATE",
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runClickupOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type ClickupFixtures = {
|
||||
/**
|
||||
* A pre-connected ClickUp connector inside the fixture's `searchSpace`.
|
||||
* A pre-connected ClickUp connector inside the fixture's `workspace`.
|
||||
* OAuth and MCP tool calls use E2E ClickUp fakes and are cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
clickupConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const clickupFixtures = searchSpaceFixtures.extend<ClickupFixtures>({
|
||||
clickupConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runClickupOAuth(request, apiToken, searchSpace.id);
|
||||
export const clickupFixtures = workspaceFixtures.extend<ClickupFixtures>({
|
||||
clickupConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runClickupOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"clickupConnector fixture: OAuth completed but no CLICKUP_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -1,23 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runComposioOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type ComposioCalendarFixtures = {
|
||||
/**
|
||||
* A pre-connected Composio Google Calendar connector inside the
|
||||
* fixture's `searchSpace`. OAuth uses the strict fake and is cleaned
|
||||
* fixture's `workspace`. OAuth uses the strict fake and is cleaned
|
||||
* up automatically after the test.
|
||||
*/
|
||||
composioCalendarConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const composioCalendarFixtures = searchSpaceFixtures.extend<ComposioCalendarFixtures>({
|
||||
composioCalendarConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runComposioOAuth(
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace.id,
|
||||
"googlecalendar"
|
||||
);
|
||||
export const composioCalendarFixtures = workspaceFixtures.extend<ComposioCalendarFixtures>({
|
||||
composioCalendarConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runComposioOAuth(request, apiToken, workspace.id, "googlecalendar");
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"composioCalendarConnector fixture: OAuth completed but no connector was created. " +
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runComposioOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type ComposioDriveFixtures = {
|
||||
/**
|
||||
* A pre-connected Composio Google Drive connector inside the
|
||||
* fixture's `searchSpace`. OAuth happens against the strict fake
|
||||
* fixture's `workspace`. OAuth happens against the strict fake
|
||||
* (no real network). Cleaned up automatically after the test.
|
||||
*/
|
||||
composioDriveConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const composioDriveFixtures = searchSpaceFixtures.extend<ComposioDriveFixtures>({
|
||||
composioDriveConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runComposioOAuth(request, apiToken, searchSpace.id, "googledrive");
|
||||
export const composioDriveFixtures = workspaceFixtures.extend<ComposioDriveFixtures>({
|
||||
composioDriveConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runComposioOAuth(request, apiToken, workspace.id, "googledrive");
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"composioDriveConnector fixture: OAuth completed but no connector was created. " +
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runComposioOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type ComposioGmailFixtures = {
|
||||
/**
|
||||
* A pre-connected Composio Gmail connector inside the fixture's
|
||||
* `searchSpace`. OAuth happens against the strict fake (no real
|
||||
* `workspace`. OAuth happens against the strict fake (no real
|
||||
* network). Cleaned up automatically after the test.
|
||||
*/
|
||||
composioGmailConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const composioGmailFixtures = searchSpaceFixtures.extend<ComposioGmailFixtures>({
|
||||
composioGmailConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runComposioOAuth(request, apiToken, searchSpace.id, "gmail");
|
||||
export const composioGmailFixtures = workspaceFixtures.extend<ComposioGmailFixtures>({
|
||||
composioGmailConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runComposioOAuth(request, apiToken, workspace.id, "gmail");
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"composioGmailConnector fixture: OAuth completed but no connector was created. " +
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ import {
|
|||
deleteConnector,
|
||||
runConfluenceOAuth,
|
||||
} from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type ConfluenceFixtures = {
|
||||
/**
|
||||
* A pre-connected Confluence connector inside the fixture's `searchSpace`.
|
||||
* A pre-connected Confluence connector inside the fixture's `workspace`.
|
||||
* OAuth uses E2E Atlassian fakes and is cleaned up automatically after
|
||||
* the test.
|
||||
*/
|
||||
confluenceConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const confluenceFixtures = searchSpaceFixtures.extend<ConfluenceFixtures>({
|
||||
confluenceConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runConfluenceOAuth(request, apiToken, searchSpace.id);
|
||||
export const confluenceFixtures = workspaceFixtures.extend<ConfluenceFixtures>({
|
||||
confluenceConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runConfluenceOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"confluenceConnector fixture: OAuth completed but no CONFLUENCE_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runJiraOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type JiraFixtures = {
|
||||
/**
|
||||
* A pre-connected Jira connector inside the fixture's `searchSpace`.
|
||||
* A pre-connected Jira connector inside the fixture's `workspace`.
|
||||
* OAuth and MCP tool calls use E2E Jira fakes and are cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
jiraConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const jiraFixtures = searchSpaceFixtures.extend<JiraFixtures>({
|
||||
jiraConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runJiraOAuth(request, apiToken, searchSpace.id);
|
||||
export const jiraFixtures = workspaceFixtures.extend<JiraFixtures>({
|
||||
jiraConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runJiraOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"jiraConnector fixture: OAuth completed but no JIRA_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runLinearOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type LinearFixtures = {
|
||||
/**
|
||||
* A pre-connected Linear connector inside the fixture's `searchSpace`.
|
||||
* A pre-connected Linear connector inside the fixture's `workspace`.
|
||||
* OAuth and MCP tool calls use E2E Linear fakes and are cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
linearConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const linearFixtures = searchSpaceFixtures.extend<LinearFixtures>({
|
||||
linearConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runLinearOAuth(request, apiToken, searchSpace.id);
|
||||
export const linearFixtures = workspaceFixtures.extend<LinearFixtures>({
|
||||
linearConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runLinearOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"linearConnector fixture: OAuth completed but no LINEAR_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ import {
|
|||
deleteConnector,
|
||||
runNativeGoogleCalendarOAuth,
|
||||
} from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type NativeCalendarFixtures = {
|
||||
/**
|
||||
* A pre-connected native Google Calendar connector inside the fixture's
|
||||
* `searchSpace`. OAuth uses E2E native Google fakes and is cleaned up
|
||||
* `workspace`. OAuth uses E2E native Google fakes and is cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
nativeCalendarConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const nativeCalendarFixtures = searchSpaceFixtures.extend<NativeCalendarFixtures>({
|
||||
nativeCalendarConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runNativeGoogleCalendarOAuth(request, apiToken, searchSpace.id);
|
||||
export const nativeCalendarFixtures = workspaceFixtures.extend<NativeCalendarFixtures>({
|
||||
nativeCalendarConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runNativeGoogleCalendarOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"nativeCalendarConnector fixture: OAuth completed but no GOOGLE_CALENDAR_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ import {
|
|||
deleteConnector,
|
||||
runNativeGoogleDriveOAuth,
|
||||
} from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type NativeDriveFixtures = {
|
||||
/**
|
||||
* A pre-connected native Google Drive connector inside the fixture's
|
||||
* `searchSpace`. OAuth uses E2E native Google fakes and is cleaned up
|
||||
* `workspace`. OAuth uses E2E native Google fakes and is cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
nativeDriveConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const nativeDriveFixtures = searchSpaceFixtures.extend<NativeDriveFixtures>({
|
||||
nativeDriveConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runNativeGoogleDriveOAuth(request, apiToken, searchSpace.id);
|
||||
export const nativeDriveFixtures = workspaceFixtures.extend<NativeDriveFixtures>({
|
||||
nativeDriveConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runNativeGoogleDriveOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"nativeDriveConnector fixture: OAuth completed but no GOOGLE_DRIVE_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ import {
|
|||
deleteConnector,
|
||||
runNativeDropboxOAuth,
|
||||
} from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type NativeDropboxFixtures = {
|
||||
/**
|
||||
* A pre-connected native Dropbox connector inside the fixture's
|
||||
* `searchSpace`. OAuth uses E2E Dropbox fakes and is cleaned up
|
||||
* `workspace`. OAuth uses E2E Dropbox fakes and is cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
nativeDropboxConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const nativeDropboxFixtures = searchSpaceFixtures.extend<NativeDropboxFixtures>({
|
||||
nativeDropboxConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runNativeDropboxOAuth(request, apiToken, searchSpace.id);
|
||||
export const nativeDropboxFixtures = workspaceFixtures.extend<NativeDropboxFixtures>({
|
||||
nativeDropboxConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runNativeDropboxOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"nativeDropboxConnector fixture: OAuth completed but no DROPBOX_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ import {
|
|||
deleteConnector,
|
||||
runNativeGoogleGmailOAuth,
|
||||
} from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type NativeGmailFixtures = {
|
||||
/**
|
||||
* A pre-connected native Google Gmail connector inside the fixture's
|
||||
* `searchSpace`. OAuth uses E2E native Google fakes and is cleaned up
|
||||
* `workspace`. OAuth uses E2E native Google fakes and is cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
nativeGmailConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const nativeGmailFixtures = searchSpaceFixtures.extend<NativeGmailFixtures>({
|
||||
nativeGmailConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runNativeGoogleGmailOAuth(request, apiToken, searchSpace.id);
|
||||
export const nativeGmailFixtures = workspaceFixtures.extend<NativeGmailFixtures>({
|
||||
nativeGmailConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runNativeGoogleGmailOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"nativeGmailConnector fixture: OAuth completed but no GOOGLE_GMAIL_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ import {
|
|||
deleteConnector,
|
||||
runNativeOneDriveOAuth,
|
||||
} from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type NativeOneDriveFixtures = {
|
||||
/**
|
||||
* A pre-connected native Microsoft OneDrive connector inside the
|
||||
* fixture's `searchSpace`. OAuth uses E2E Microsoft Graph fakes and is
|
||||
* fixture's `workspace`. OAuth uses E2E Microsoft Graph fakes and is
|
||||
* cleaned up automatically after the test.
|
||||
*/
|
||||
nativeOneDriveConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const nativeOneDriveFixtures = searchSpaceFixtures.extend<NativeOneDriveFixtures>({
|
||||
nativeOneDriveConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runNativeOneDriveOAuth(request, apiToken, searchSpace.id);
|
||||
export const nativeOneDriveFixtures = workspaceFixtures.extend<NativeOneDriveFixtures>({
|
||||
nativeOneDriveConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runNativeOneDriveOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"nativeOneDriveConnector fixture: OAuth completed but no ONEDRIVE_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import { type ConnectorRow, deleteConnector, runNotionOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type NotionFixtures = {
|
||||
/**
|
||||
* A pre-connected Notion connector inside the fixture's `searchSpace`.
|
||||
* A pre-connected Notion connector inside the fixture's `workspace`.
|
||||
* OAuth uses E2E Notion fakes and is cleaned up automatically after the test.
|
||||
*/
|
||||
notionConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const notionFixtures = searchSpaceFixtures.extend<NotionFixtures>({
|
||||
notionConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runNotionOAuth(request, apiToken, searchSpace.id);
|
||||
export const notionFixtures = workspaceFixtures.extend<NotionFixtures>({
|
||||
notionConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runNotionOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"notionConnector fixture: OAuth completed but no NOTION_CONNECTOR was created. " +
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { type ConnectorRow, deleteConnector, runSlackOAuth } from "../../helpers/api/connectors";
|
||||
import { searchSpaceFixtures } from "../workspace.fixture";
|
||||
import { workspaceFixtures } from "../workspace.fixture";
|
||||
|
||||
export type SlackFixtures = {
|
||||
/**
|
||||
* A pre-connected Slack connector inside the fixture's `searchSpace`.
|
||||
* A pre-connected Slack connector inside the fixture's `workspace`.
|
||||
* OAuth and MCP tool calls use E2E Slack fakes and are cleaned up
|
||||
* automatically after the test.
|
||||
*/
|
||||
slackConnector: ConnectorRow;
|
||||
};
|
||||
|
||||
export const slackFixtures = searchSpaceFixtures.extend<SlackFixtures>({
|
||||
slackConnector: async ({ request, apiToken, searchSpace }, use) => {
|
||||
const { connector } = await runSlackOAuth(request, apiToken, searchSpace.id);
|
||||
export const slackFixtures = workspaceFixtures.extend<SlackFixtures>({
|
||||
slackConnector: async ({ request, apiToken, workspace }, use) => {
|
||||
const { connector } = await runSlackOAuth(request, apiToken, workspace.id);
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
"slackConnector fixture: OAuth completed but no SLACK_CONNECTOR was created. " +
|
||||
|
|
|
|||
16
surfsense_web/tests/fixtures/index.ts
vendored
16
surfsense_web/tests/fixtures/index.ts
vendored
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* Inheritance chain:
|
||||
* base (@playwright/test)
|
||||
* └─ searchSpaceFixtures — apiToken, searchSpace
|
||||
* └─ workspaceFixtures — apiToken, workspace
|
||||
* ├─ composioDriveFixtures — composioDriveConnector
|
||||
* │ └─ composioDriveWithChatTest — chatThread
|
||||
* └─ composioGmailFixtures — composioGmailConnector
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
* └─ clickupWithChatTest — chatThread
|
||||
* └─ slackFixtures — slackConnector
|
||||
* └─ slackWithChatTest — chatThread
|
||||
* └─ manualUploadWithChatTest — chatThread (no connector; uses base search space)
|
||||
* └─ manualUploadWithChatTest — chatThread (no connector; uses base workspace)
|
||||
*
|
||||
* To add a new connector (Gmail, Slack, manual upload, etc.):
|
||||
* 1. Add a fixture file under `fixtures/connectors/<name>.fixture.ts`.
|
||||
|
|
@ -59,7 +59,7 @@ export { nativeGmailFixtures } from "./connectors/native-gmail.fixture";
|
|||
export { nativeOneDriveFixtures } from "./connectors/native-onedrive.fixture";
|
||||
export { notionFixtures } from "./connectors/notion.fixture";
|
||||
export { slackFixtures } from "./connectors/slack.fixture";
|
||||
export { searchSpaceFixtures } from "./workspace.fixture";
|
||||
export { workspaceFixtures } from "./workspace.fixture";
|
||||
|
||||
import { type ChatThreadFixtures, chatThreadFixtures } from "./chat-thread.fixture";
|
||||
import { clickupFixtures } from "./connectors/clickup.fixture";
|
||||
|
|
@ -76,10 +76,10 @@ import { nativeGmailFixtures } from "./connectors/native-gmail.fixture";
|
|||
import { nativeOneDriveFixtures } from "./connectors/native-onedrive.fixture";
|
||||
import { notionFixtures } from "./connectors/notion.fixture";
|
||||
import { slackFixtures } from "./connectors/slack.fixture";
|
||||
import { searchSpaceFixtures } from "./workspace.fixture";
|
||||
import { workspaceFixtures } from "./workspace.fixture";
|
||||
|
||||
/** Default `test` for specs that just need auth + a clean search space. */
|
||||
export const test = searchSpaceFixtures;
|
||||
/** Default `test` for specs that just need auth + a clean workspace. */
|
||||
export const test = workspaceFixtures;
|
||||
/** `test` for specs that also need a pre-connected Composio Drive connector. */
|
||||
export const composioDriveTest = composioDriveFixtures;
|
||||
/** `test` for Drive specs that also need a chat thread. */
|
||||
|
|
@ -149,7 +149,7 @@ export const slackWithChatTest = slackFixtures.extend<ChatThreadFixtures>(chatTh
|
|||
* `test` for manual upload specs that also need a chat thread.
|
||||
*
|
||||
* Manual upload has no connector fixture — the user uploads files directly via
|
||||
* the Documents-sidebar UI — so this composes chat onto the bare search-space.
|
||||
* the Documents-sidebar UI — so this composes chat onto the bare workspace.
|
||||
*/
|
||||
export const manualUploadWithChatTest =
|
||||
searchSpaceFixtures.extend<ChatThreadFixtures>(chatThreadFixtures);
|
||||
workspaceFixtures.extend<ChatThreadFixtures>(chatThreadFixtures);
|
||||
|
|
|
|||
|
|
@ -2,24 +2,20 @@ import fs from "node:fs";
|
|||
import path from "node:path";
|
||||
import { test as base } from "@playwright/test";
|
||||
import { acquireTestToken } from "../helpers/api/auth";
|
||||
import {
|
||||
createSearchSpace,
|
||||
deleteSearchSpace,
|
||||
type SearchSpaceRow,
|
||||
} from "../helpers/api/workspaces";
|
||||
import { uniqueSearchSpaceName } from "../helpers/canary";
|
||||
import { createWorkspace, deleteWorkspace, type WorkspaceRow } from "../helpers/api/workspaces";
|
||||
import { uniqueWorkspaceName } from "../helpers/canary";
|
||||
|
||||
export type SearchSpaceFixtures = {
|
||||
export type WorkspaceFixtures = {
|
||||
/**
|
||||
* Bearer token for the seeded test user. Worker-scoped so we only
|
||||
* log in once per worker (logins are cheap, but caching is cheaper).
|
||||
*/
|
||||
apiToken: string;
|
||||
/**
|
||||
* A fresh, named search space for the current test. Cleaned up
|
||||
* A fresh, named workspace for the current test. Cleaned up
|
||||
* automatically after the test finishes.
|
||||
*/
|
||||
searchSpace: SearchSpaceRow;
|
||||
workspace: WorkspaceRow;
|
||||
};
|
||||
|
||||
const SESSION_COOKIE_NAME = process.env.SESSION_COOKIE_NAME || "surfsense_session";
|
||||
|
|
@ -45,7 +41,7 @@ function loadCachedSessionToken(): string | null {
|
|||
return null;
|
||||
}
|
||||
|
||||
export const searchSpaceFixtures = base.extend<SearchSpaceFixtures, { apiTokenWorker: string }>({
|
||||
export const workspaceFixtures = base.extend<WorkspaceFixtures, { apiTokenWorker: string }>({
|
||||
apiTokenWorker: [
|
||||
async ({ playwright }, use) => {
|
||||
const cached = loadCachedSessionToken();
|
||||
|
|
@ -66,16 +62,16 @@ export const searchSpaceFixtures = base.extend<SearchSpaceFixtures, { apiTokenWo
|
|||
apiToken: async ({ apiTokenWorker }, use) => {
|
||||
await use(apiTokenWorker);
|
||||
},
|
||||
searchSpace: async ({ request, apiToken }, use) => {
|
||||
const space = await createSearchSpace(
|
||||
workspace: async ({ request, apiToken }, use) => {
|
||||
const space = await createWorkspace(
|
||||
request,
|
||||
apiToken,
|
||||
uniqueSearchSpaceName("composio-drive-e2e")
|
||||
uniqueWorkspaceName("composio-drive-e2e")
|
||||
);
|
||||
try {
|
||||
await use(space);
|
||||
} finally {
|
||||
await deleteSearchSpace(request, apiToken, space.id);
|
||||
await deleteWorkspace(request, apiToken, space.id);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|||
export async function streamChatToCompletion(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
args: { searchSpaceId: number; threadId: number; query: string }
|
||||
args: { workspaceId: number; threadId: number; query: string }
|
||||
): Promise<ChatStreamResult> {
|
||||
const response = await request.post(`${BACKEND_URL}/api/v1/new_chat`, {
|
||||
headers: authHeaders(token),
|
||||
data: {
|
||||
chat_id: args.threadId,
|
||||
workspace_id: args.searchSpaceId,
|
||||
workspace_id: args.workspaceId,
|
||||
user_query: args.query,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ export type ConnectorRow = {
|
|||
export async function listConnectors(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<ConnectorRow[]> {
|
||||
const response = await request.get(
|
||||
`${BACKEND_URL}/api/v1/search-source-connectors?workspace_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/search-source-connectors?workspace_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!response.ok()) {
|
||||
|
|
@ -111,11 +111,11 @@ export async function triggerIndex(
|
|||
request: APIRequestContext,
|
||||
token: string,
|
||||
connectorId: number,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
body: IndexBody
|
||||
): Promise<{ ok: true }> {
|
||||
const response = await request.post(
|
||||
`${BACKEND_URL}/api/v1/search-source-connectors/${connectorId}/index?workspace_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/search-source-connectors/${connectorId}/index?workspace_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token), data: body }
|
||||
);
|
||||
if (!response.ok()) {
|
||||
|
|
@ -130,11 +130,11 @@ export async function triggerIndexExpectDisabled(
|
|||
request: APIRequestContext,
|
||||
token: string,
|
||||
connectorId: number,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
body: IndexBody = {}
|
||||
): Promise<{ indexing_started: false; message?: string }> {
|
||||
const response = await request.post(
|
||||
`${BACKEND_URL}/api/v1/search-source-connectors/${connectorId}/index?workspace_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/search-source-connectors/${connectorId}/index?workspace_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token), data: body }
|
||||
);
|
||||
if (!response.ok()) {
|
||||
|
|
@ -166,7 +166,7 @@ export async function triggerIndexExpectDisabled(
|
|||
export async function runComposioOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
toolkitId: "googledrive" | "gmail" | "googlecalendar" = "googledrive"
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
|
|
@ -175,7 +175,7 @@ export async function runComposioOAuth(
|
|||
}> {
|
||||
// Step 1: kick off OAuth, get auth_url.
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/composio/connector/add?space_id=${searchSpaceId}&toolkit_id=${toolkitId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/composio/connector/add?space_id=${workspaceId}&toolkit_id=${toolkitId}`,
|
||||
{
|
||||
headers: authHeaders(token),
|
||||
}
|
||||
|
|
@ -202,7 +202,7 @@ export async function runComposioOAuth(
|
|||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
// Step 3: look up the resulting connector (if any).
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const composioType =
|
||||
toolkitId === "googledrive"
|
||||
? "COMPOSIO_GOOGLE_DRIVE_CONNECTOR"
|
||||
|
|
@ -223,14 +223,14 @@ export async function runComposioOAuth(
|
|||
export async function runNativeGoogleDriveOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/google/drive/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/google/drive/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -250,7 +250,7 @@ export async function runNativeGoogleDriveOAuth(
|
|||
});
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "GOOGLE_DRIVE_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -266,14 +266,14 @@ export async function runNativeGoogleDriveOAuth(
|
|||
export async function runNativeOneDriveOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/onedrive/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/onedrive/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -306,7 +306,7 @@ export async function runNativeOneDriveOAuth(
|
|||
}
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "ONEDRIVE_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -322,14 +322,14 @@ export async function runNativeOneDriveOAuth(
|
|||
export async function runNativeDropboxOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/dropbox/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/dropbox/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -362,7 +362,7 @@ export async function runNativeDropboxOAuth(
|
|||
}
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "DROPBOX_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -377,14 +377,14 @@ export async function runNativeDropboxOAuth(
|
|||
export async function runNativeGoogleGmailOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/google/gmail/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/google/gmail/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -404,7 +404,7 @@ export async function runNativeGoogleGmailOAuth(
|
|||
});
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "GOOGLE_GMAIL_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -419,14 +419,14 @@ export async function runNativeGoogleGmailOAuth(
|
|||
export async function runNativeGoogleCalendarOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/google/calendar/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/google/calendar/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -446,7 +446,7 @@ export async function runNativeGoogleCalendarOAuth(
|
|||
});
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector =
|
||||
connectors.find((c) => c.connector_type === "GOOGLE_CALENDAR_CONNECTOR") ?? null;
|
||||
|
||||
|
|
@ -464,14 +464,14 @@ export async function runNativeGoogleCalendarOAuth(
|
|||
export async function runNotionOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/notion/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/notion/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -499,7 +499,7 @@ export async function runNotionOAuth(
|
|||
);
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "NOTION_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -518,14 +518,14 @@ export async function runNotionOAuth(
|
|||
export async function runConfluenceOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/confluence/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/confluence/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -553,7 +553,7 @@ export async function runConfluenceOAuth(
|
|||
);
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "CONFLUENCE_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -568,14 +568,14 @@ export async function runConfluenceOAuth(
|
|||
export async function runLinearOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/linear/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/linear/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -603,7 +603,7 @@ export async function runLinearOAuth(
|
|||
);
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "LINEAR_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -618,14 +618,14 @@ export async function runLinearOAuth(
|
|||
export async function runJiraOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/jira/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/jira/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -653,7 +653,7 @@ export async function runJiraOAuth(
|
|||
);
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "JIRA_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -668,14 +668,14 @@ export async function runJiraOAuth(
|
|||
export async function runClickupOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/clickup/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/clickup/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -703,7 +703,7 @@ export async function runClickupOAuth(
|
|||
);
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "CLICKUP_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
@ -718,14 +718,14 @@ export async function runClickupOAuth(
|
|||
export async function runSlackOAuth(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number
|
||||
workspaceId: number
|
||||
): Promise<{
|
||||
authUrl: string;
|
||||
finalUrl: string;
|
||||
connector: ConnectorRow | null;
|
||||
}> {
|
||||
const initiateResp = await request.get(
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/slack/connector/add?space_id=${searchSpaceId}`,
|
||||
`${BACKEND_URL}/api/v1/auth/mcp/slack/connector/add?space_id=${workspaceId}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!initiateResp.ok()) {
|
||||
|
|
@ -758,7 +758,7 @@ export async function runSlackOAuth(
|
|||
}
|
||||
const location = callbackResp.headers().location ?? auth_url;
|
||||
|
||||
const connectors = await listConnectors(request, token, searchSpaceId);
|
||||
const connectors = await listConnectors(request, token, workspaceId);
|
||||
const connector = connectors.find((c) => c.connector_type === "SLACK_CONNECTOR") ?? null;
|
||||
|
||||
return { authUrl: auth_url, finalUrl: location, connector };
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ type Paginated<T> = {
|
|||
export async function listDocuments(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
limit = 100
|
||||
): Promise<DocumentRow[]> {
|
||||
const response = await request.get(
|
||||
`${BACKEND_URL}/api/v1/documents?workspace_id=${searchSpaceId}&limit=${limit}`,
|
||||
`${BACKEND_URL}/api/v1/documents?workspace_id=${workspaceId}&limit=${limit}`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!response.ok()) {
|
||||
|
|
@ -51,11 +51,11 @@ export type EditorContent = {
|
|||
export async function getEditorContent(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
documentId: number
|
||||
): Promise<EditorContent> {
|
||||
const response = await request.get(
|
||||
`${BACKEND_URL}/api/v1/workspaces/${searchSpaceId}/documents/${documentId}/editor-content`,
|
||||
`${BACKEND_URL}/api/v1/workspaces/${workspaceId}/documents/${documentId}/editor-content`,
|
||||
{ headers: authHeaders(token) }
|
||||
);
|
||||
if (!response.ok()) {
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
import type { APIRequestContext } from "@playwright/test";
|
||||
import { authHeaders, BACKEND_URL } from "./auth";
|
||||
|
||||
export type SearchSpaceRow = {
|
||||
export type WorkspaceRow = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string | null;
|
||||
};
|
||||
|
||||
export async function createSearchSpace(
|
||||
export async function createWorkspace(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
name: string,
|
||||
description = "E2E test search space"
|
||||
): Promise<SearchSpaceRow> {
|
||||
description = "E2E test workspace"
|
||||
): Promise<WorkspaceRow> {
|
||||
const response = await request.post(`${BACKEND_URL}/api/v1/workspaces`, {
|
||||
headers: authHeaders(token),
|
||||
data: { name, description },
|
||||
});
|
||||
if (!response.ok()) {
|
||||
throw new Error(`createSearchSpace failed (${response.status()}): ${await response.text()}`);
|
||||
throw new Error(`createWorkspace failed (${response.status()}): ${await response.text()}`);
|
||||
}
|
||||
return (await response.json()) as SearchSpaceRow;
|
||||
return (await response.json()) as WorkspaceRow;
|
||||
}
|
||||
|
||||
export async function deleteSearchSpace(
|
||||
export async function deleteWorkspace(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
id: number
|
||||
|
|
@ -34,7 +34,7 @@ export async function deleteSearchSpace(
|
|||
if (!response.ok() && response.status() !== 404) {
|
||||
// 404 is acceptable: the test may have already deleted the space.
|
||||
throw new Error(
|
||||
`deleteSearchSpace(${id}) failed (${response.status()}): ${await response.text()}`
|
||||
`deleteWorkspace(${id}) failed (${response.status()}): ${await response.text()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ export const FAKE_CLICKUP_TASKS = {
|
|||
},
|
||||
} as const;
|
||||
|
||||
/** Generate a unique-per-run search space name. Keeps parallel tests isolated. */
|
||||
export function uniqueSearchSpaceName(prefix = "e2e"): string {
|
||||
/** Generate a unique-per-run workspace name. Keeps parallel tests isolated. */
|
||||
export function uniqueWorkspaceName(prefix = "e2e"): string {
|
||||
return `${prefix}-${randomUUID().slice(0, 8)}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ import { expect } from "@playwright/test";
|
|||
* route changes only require an update in one place.
|
||||
*/
|
||||
|
||||
export function newChatUrl(searchSpaceId: number): string {
|
||||
return `/dashboard/${searchSpaceId}/new-chat`;
|
||||
export function newChatUrl(workspaceId: number): string {
|
||||
return `/dashboard/${workspaceId}/new-chat`;
|
||||
}
|
||||
|
||||
export function connectorsCallbackUrl(searchSpaceId: number): string {
|
||||
return `/dashboard/${searchSpaceId}/connectors/callback`;
|
||||
export function connectorsCallbackUrl(workspaceId: number): string {
|
||||
return `/dashboard/${workspaceId}/connectors/callback`;
|
||||
}
|
||||
|
||||
export async function gotoNewChat(page: Page, searchSpaceId: number): Promise<void> {
|
||||
const target = newChatUrl(searchSpaceId);
|
||||
export async function gotoNewChat(page: Page, workspaceId: number): Promise<void> {
|
||||
const target = newChatUrl(workspaceId);
|
||||
await page.goto(target, { waitUntil: "domcontentloaded" });
|
||||
await expect(page).toHaveURL((url) => url.pathname === target);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export async function waitForIndexingComplete(
|
|||
request: APIRequestContext,
|
||||
token: string,
|
||||
connectorId: number,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
options: { timeoutMs?: number; intervalMs?: number; minDocuments?: number } = {}
|
||||
): Promise<void> {
|
||||
const timeoutMs = options.timeoutMs ?? 60_000;
|
||||
|
|
@ -23,7 +23,7 @@ export async function waitForIndexingComplete(
|
|||
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const connector = await getConnector(request, token, connectorId);
|
||||
const docs = await listDocuments(request, token, searchSpaceId);
|
||||
const docs = await listDocuments(request, token, workspaceId);
|
||||
const readyDocs = docs.filter(isDocumentReady);
|
||||
|
||||
const connectorIndexed = connector.last_indexed_at !== null;
|
||||
|
|
@ -39,19 +39,19 @@ export async function waitForIndexingComplete(
|
|||
|
||||
throw new Error(
|
||||
`waitForIndexingComplete: timed out after ${timeoutMs}ms waiting for ` +
|
||||
`connector ${connectorId} in space ${searchSpaceId}. Last observed: ${lastState}`
|
||||
`connector ${connectorId} in space ${workspaceId}. Last observed: ${lastState}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls until the given document title appears in the search space with
|
||||
* Polls until the given document title appears in the workspace with
|
||||
* status=ready. Useful when a spec wants to assert on a specific file
|
||||
* by name rather than count.
|
||||
*/
|
||||
export async function waitForDocumentByTitle(
|
||||
request: APIRequestContext,
|
||||
token: string,
|
||||
searchSpaceId: number,
|
||||
workspaceId: number,
|
||||
title: string,
|
||||
options: { timeoutMs?: number; intervalMs?: number } = {}
|
||||
): Promise<void> {
|
||||
|
|
@ -60,7 +60,7 @@ export async function waitForDocumentByTitle(
|
|||
const startedAt = Date.now();
|
||||
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const docs = await listDocuments(request, token, searchSpaceId);
|
||||
const docs = await listDocuments(request, token, workspaceId);
|
||||
const match = docs.find((d) => d.title === title && isDocumentReady(d));
|
||||
if (match) {
|
||||
return;
|
||||
|
|
@ -70,6 +70,6 @@ export async function waitForDocumentByTitle(
|
|||
|
||||
throw new Error(
|
||||
`waitForDocumentByTitle: timed out after ${timeoutMs}ms waiting for ` +
|
||||
`title=${JSON.stringify(title)} in space ${searchSpaceId}.`
|
||||
`title=${JSON.stringify(title)} in space ${workspaceId}.`
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,12 @@ import { authHeaders, BACKEND_URL } from "../helpers/api/auth";
|
|||
import { streamChatToCompletion } from "../helpers/api/chat";
|
||||
|
||||
test.describe("Smoke", () => {
|
||||
test("chat stream completes for an unrelated query", async ({
|
||||
request,
|
||||
apiToken,
|
||||
searchSpace,
|
||||
}) => {
|
||||
test("chat stream completes for an unrelated query", async ({ request, apiToken, workspace }) => {
|
||||
const threadResponse = await request.post(`${BACKEND_URL}/api/v1/threads`, {
|
||||
headers: authHeaders(apiToken),
|
||||
data: {
|
||||
title: "e2e-chat-stream-smoke",
|
||||
workspace_id: searchSpace.id,
|
||||
workspace_id: workspace.id,
|
||||
visibility: "PRIVATE",
|
||||
},
|
||||
});
|
||||
|
|
@ -20,7 +16,7 @@ test.describe("Smoke", () => {
|
|||
|
||||
const thread = (await threadResponse.json()) as { id: number };
|
||||
const chat = await streamChatToCompletion(request, apiToken, {
|
||||
searchSpaceId: searchSpace.id,
|
||||
workspaceId: workspace.id,
|
||||
threadId: thread.id,
|
||||
query: "E2E_NO_RELEVANT_CONTENT_SMOKE",
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue