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.
94 lines
3.9 KiB
TypeScript
94 lines
3.9 KiB
TypeScript
/**
|
|
* Regression test: shared dashboards must render in a fully unauthenticated browser context.
|
|
* Added after a fix that skipped "always-401" API calls in shared/exported views had to be
|
|
* reverted — the skip broke the shared dashboard render path. A logged-out goto of
|
|
* /shared/{token} reliably reproduces that class of regression.
|
|
*/
|
|
import { expect, Page } from '@playwright/test'
|
|
|
|
import { InsightVizNode, NodeKind, TrendsQuery } from '../../frontend/src/queries/schema/schema-general'
|
|
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 createSharedDashboard(
|
|
page: Page,
|
|
playwrightSetup: PlaywrightSetup,
|
|
orgName: string
|
|
): Promise<{ sharingData: SharingConfigurationType; dashboardName: string; insightName: string }> {
|
|
const workspace = await playwrightSetup.createWorkspace(orgName)
|
|
const authHeaders = {
|
|
Authorization: `Bearer ${workspace.personal_api_key}`,
|
|
'Content-Type': 'application/json',
|
|
}
|
|
|
|
const dashboardName = 'Logged-out dashboard render'
|
|
const dashboardResponse = await page.request.post(`/v1/projects/${workspace.team_id}/dashboards/`, {
|
|
headers: authHeaders,
|
|
data: { name: dashboardName },
|
|
})
|
|
expect(dashboardResponse.ok()).toBe(true)
|
|
const dashboardData = await dashboardResponse.json()
|
|
|
|
const insightName = 'Trends pageview tile'
|
|
const insightPayload: { name: string; query: InsightVizNode<TrendsQuery>; dashboards: number[] } = {
|
|
name: insightName,
|
|
query: {
|
|
kind: NodeKind.InsightVizNode,
|
|
source: {
|
|
kind: NodeKind.TrendsQuery,
|
|
series: [{ kind: NodeKind.EventsNode, event: '$pageview' }],
|
|
dateRange: { date_from: '2024-10-04', date_to: '2024-11-03', explicitDate: true },
|
|
},
|
|
},
|
|
dashboards: [dashboardData.id],
|
|
}
|
|
|
|
const insightResponse = await page.request.post(`/v1/projects/${workspace.team_id}/insights/`, {
|
|
headers: authHeaders,
|
|
data: insightPayload,
|
|
})
|
|
expect(insightResponse.ok()).toBe(true)
|
|
|
|
const sharingResponse = await page.request.patch(
|
|
`/v1/projects/${workspace.team_id}/dashboards/${dashboardData.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, dashboardName, insightName }
|
|
}
|
|
|
|
test.describe('Shared dashboard (unauthenticated)', () => {
|
|
test('renders successfully in a logged-out browser context', async ({ browser, page, playwrightSetup }) => {
|
|
const { sharingData, dashboardName, insightName } = await createSharedDashboard(
|
|
page,
|
|
playwrightSetup,
|
|
'Unauth Shared Dashboard 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=${dashboardName}`)).toBeVisible({ timeout: 30000 })
|
|
await expect(unauthPage.locator(`text=${insightName}`)).toBeVisible({ timeout: 30000 })
|
|
await expect(unauthPage.locator('[data-attr="insights-graph"]').first()).toBeVisible({ timeout: 30000 })
|
|
|
|
expectNoTeamScopedApiLeaks(failedApiResponses)
|
|
} finally {
|
|
await unauthContext.close()
|
|
}
|
|
})
|
|
})
|