mirror of
https://github.com/hanzoai/insights.git
synced 2026-10-30 16:15:31 +00:00
Every first-party Python caller and test now names the mount the API actually answers on. Mechanical: URL literals only, and only where the /api/ was ours -- a preceding word character means it was a module path like insights/api/ or a third-party host like slack.com/api/, and those are untouched. Left saying /api/, each for a reason rather than for safety: - products/warehouse_sources/.../sources/** is a catalogue of vendor endpoints - services/llm-gateway deploys separately and is under a code freeze, so moving its two calls would break it during the skew - the mcp_store and Slack/Teams redirect_uris are registered with third parties and must byte-match what was registered - the Wizard and Raycast client-metadata paths are OAuth client_ids - /api/surveys and /api/feature_flag/local_evaluation are SDK aliases the ingress routes to the Rust fleets, held by released SDK versions Test URLconfs moved with the requests that call them, and the Datastore user-selection fixtures now carry the leading slash that request.path has.
88 lines
3.4 KiB
TypeScript
88 lines
3.4 KiB
TypeScript
/**
|
|
* Regression test: shared notebooks must render in a fully unauthenticated browser context.
|
|
* Sibling to shared-dashboard-unauthenticated.spec.ts — ensures the ExporterNotebookScene
|
|
* code path keeps working when the exporter bundle / shared-view skipping evolves.
|
|
*/
|
|
import { expect, Page } from '@playwright/test'
|
|
|
|
import { SharingConfigurationType } from '../../frontend/src/types'
|
|
import { PlaywrightSetup } from '../utils/playwright-setup'
|
|
import { expectNoTeamScopedApiLeaks, openUnauthenticatedSharedPage } from '../utils/sharedViewExpectations'
|
|
import { test } from '../utils/workspace-test-base'
|
|
|
|
async function createSharedNotebook(
|
|
page: Page,
|
|
playwrightSetup: PlaywrightSetup,
|
|
orgName: string
|
|
): Promise<{ sharingData: SharingConfigurationType; notebookTitle: string; paragraphText: string }> {
|
|
const workspace = await playwrightSetup.createWorkspace(orgName)
|
|
const authHeaders = {
|
|
Authorization: `Bearer ${workspace.personal_api_key}`,
|
|
'Content-Type': 'application/json',
|
|
}
|
|
|
|
const notebookTitle = 'Logged-out notebook render'
|
|
const paragraphText = 'Anonymous notebook body content'
|
|
const notebookContent = {
|
|
type: 'doc',
|
|
content: [
|
|
{
|
|
type: 'heading',
|
|
attrs: { level: 1 },
|
|
content: [{ type: 'text', text: notebookTitle }],
|
|
},
|
|
{
|
|
type: 'paragraph',
|
|
content: [{ type: 'text', text: paragraphText }],
|
|
},
|
|
],
|
|
}
|
|
|
|
const notebookResponse = await page.request.post(`/v1/projects/${workspace.team_id}/notebooks/`, {
|
|
headers: authHeaders,
|
|
data: { title: notebookTitle, content: notebookContent },
|
|
})
|
|
expect(notebookResponse.ok()).toBe(true)
|
|
const notebookData = await notebookResponse.json()
|
|
expect(notebookData.short_id).toBeTruthy()
|
|
|
|
const sharingResponse = await page.request.patch(
|
|
`/v1/projects/${workspace.team_id}/notebooks/${notebookData.short_id}/sharing/`,
|
|
{
|
|
headers: authHeaders,
|
|
data: { enabled: true },
|
|
}
|
|
)
|
|
expect(sharingResponse.ok()).toBe(true)
|
|
const sharingData: SharingConfigurationType = await sharingResponse.json()
|
|
expect(sharingData.access_token).toBeTruthy()
|
|
expect(sharingData.enabled).toBe(true)
|
|
|
|
return { sharingData, notebookTitle, paragraphText }
|
|
}
|
|
|
|
test.describe('Shared notebook (unauthenticated)', () => {
|
|
test('renders successfully in a logged-out browser context', async ({ browser, page, playwrightSetup }) => {
|
|
const { sharingData, notebookTitle, paragraphText } = await createSharedNotebook(
|
|
page,
|
|
playwrightSetup,
|
|
'Unauth Shared Notebook Test Org'
|
|
)
|
|
|
|
const unauthContext = await browser.newContext({ storageState: { cookies: [], origins: [] } })
|
|
const { unauthPage, failedApiResponses } = await openUnauthenticatedSharedPage(unauthContext)
|
|
|
|
try {
|
|
await unauthPage.goto(`/shared/${sharingData.access_token}`)
|
|
|
|
await expect(unauthPage.locator('body.ExporterBody')).toBeVisible()
|
|
await expect(unauthPage.locator(`text=${notebookTitle}`).first()).toBeVisible({ timeout: 30000 })
|
|
await expect(unauthPage.locator(`text=${paragraphText}`)).toBeVisible({ timeout: 30000 })
|
|
|
|
expectNoTeamScopedApiLeaks(failedApiResponses)
|
|
} finally {
|
|
await unauthContext.close()
|
|
}
|
|
})
|
|
})
|