@@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// A module's pages above a project (F10): `/<org>/<workspace>/modules/<module>/...`. Signed out is a redirect,
|
||||
// a workspace the person cannot see is the same 404 as one that does not exist, a missing permission is a 403
|
||||
// before `load` runs, and `load` receives the query string. `e2e/workspace-pages.spec.ts` proves the same four
|
||||
// answers over a build on a real Postgres; these say which line gives each one.
|
||||
|
||||
import { AppError } from "@conusai-kit/core"
|
||||
import { isNotFound, isRedirect } from "@tanstack/react-router"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
requestContext: vi.fn(),
|
||||
callByName: vi.fn(),
|
||||
setResponseHeader: vi.fn<(name: string, value: string) => void>(),
|
||||
load: vi.fn(),
|
||||
call: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("@tanstack/react-start/server", () => ({
|
||||
getRequest: () => {
|
||||
throw new Error("the tests pass their request")
|
||||
},
|
||||
setResponseStatus: vi.fn(),
|
||||
setResponseHeader: mocks.setResponseHeader,
|
||||
}))
|
||||
vi.mock("../apps/web/src/server/request", () => ({ requestContext: mocks.requestContext }))
|
||||
vi.mock("../apps/web/src/server/app", () => ({
|
||||
webRuntime: () => ({
|
||||
observe: { config: { errors: false } },
|
||||
selfServiceOrganizations: "members",
|
||||
registry: {
|
||||
modules: [{ id: "reports" }, { id: "unpaged" }],
|
||||
nav: [{ module: "reports", scope: "workspace", href: "reports/a/b", label: "workspace.overview" }],
|
||||
},
|
||||
env: { deployment: {} },
|
||||
}),
|
||||
}))
|
||||
vi.mock("../apps/web/src/server/tenancy-calls", () => ({ mayCreateOrganization: () => false }))
|
||||
vi.mock("../apps/web/src/server/platform-theme", () => ({ organizationThemeStyle: async () => undefined }))
|
||||
vi.mock("@conusai-kit/host/http", () => ({ csrfSessionId: () => "session", csrfToken: () => "token" }))
|
||||
vi.mock("@app/modules/pages", () => ({
|
||||
modulePages: {},
|
||||
workspacePages: {
|
||||
reports: async () => ({ permission: "reports.report.read", load: mocks.load }),
|
||||
},
|
||||
}))
|
||||
|
||||
const { workspacePageData } = await import("../apps/web/src/server/page")
|
||||
|
||||
const person = { actor: { kind: "user" } }
|
||||
const signedIn = () =>
|
||||
mocks.requestContext.mockResolvedValue({
|
||||
caller: { call: mocks.call, callByName: mocks.callByName },
|
||||
container: {},
|
||||
principal: person,
|
||||
user: { email: "ada@example.test", displayName: "Ada", locale: "en" },
|
||||
})
|
||||
const request = (): Request =>
|
||||
new Request("http://app.test/a/b/modules/reports", { headers: { "x-path": "/a/b/modules/reports" } })
|
||||
const params = { org: "a", workspace: "b", module: "reports" }
|
||||
const refusal = (status: number): AppError =>
|
||||
new AppError({ type: "/problems/refused", code: "refused", title: "Refused", status })
|
||||
const thrown = (run: Promise<unknown>): Promise<unknown> =>
|
||||
run.then(
|
||||
() => "resolved",
|
||||
(error: unknown) => error,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mocks.callByName.mockResolvedValue({ permissions: ["reports.report.read"], revision: "r1" })
|
||||
mocks.load.mockResolvedValue({ title: "Reports" })
|
||||
})
|
||||
|
||||
describe("a workspace page's loader", () => {
|
||||
it("sends a signed-out visitor to sign in, before reading anything", async () => {
|
||||
mocks.requestContext.mockResolvedValue({ caller: {}, container: {}, principal: null })
|
||||
expect(isRedirect(await thrown(workspacePageData(params, request())))).toBe(true)
|
||||
expect(mocks.load).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("hands `load` the workspace, the path below the module and the query string", async () => {
|
||||
signedIn()
|
||||
const data = await workspacePageData({ ...params, _splat: "a/b", search: "?q=one&tab=two&q=three" }, request())
|
||||
expect(mocks.load).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
slugs: { org: "a", workspace: "b" },
|
||||
segments: ["a", "b"],
|
||||
search: { q: "three", tab: "two" },
|
||||
}),
|
||||
)
|
||||
expect(data).toMatchObject({
|
||||
module: "reports",
|
||||
title: "Workspace overview · Example App",
|
||||
segments: ["a", "b"],
|
||||
locale: "en",
|
||||
data: { title: "Reports" },
|
||||
scope: { org: "a", workspace: "b" },
|
||||
seed: { permissions: ["reports.report.read"] },
|
||||
})
|
||||
})
|
||||
|
||||
it("answers 404 for a workspace of another organization, before `load`", async () => {
|
||||
signedIn()
|
||||
mocks.callByName.mockRejectedValue(refusal(404))
|
||||
expect(isNotFound(await thrown(workspacePageData(params, request())))).toBe(true)
|
||||
expect(mocks.load).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("answers 403 to a member without the page's permission, before `load`", async () => {
|
||||
signedIn()
|
||||
mocks.callByName.mockResolvedValue({ permissions: [], revision: "r1" })
|
||||
const error = (await thrown(workspacePageData(params, request()))) as { data?: unknown }
|
||||
expect(isNotFound(error)).toBe(true)
|
||||
expect(error.data).toEqual({ forbidden: true })
|
||||
expect(mocks.setResponseHeader).toHaveBeenCalledWith("x-conusai-page-status", "403")
|
||||
expect(mocks.load).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it.each([
|
||||
["no registered module", { ...params, module: "nothing" }],
|
||||
["a registered module with no workspace page", { ...params, module: "unpaged" }],
|
||||
["a name every object has", { ...params, module: "constructor" }],
|
||||
])("answers 404 for %s", async (_name, wanted) => {
|
||||
signedIn()
|
||||
expect(isNotFound(await thrown(workspacePageData(wanted, request())))).toBe(true)
|
||||
expect(mocks.load).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it.each([
|
||||
[404, undefined],
|
||||
[403, { forbidden: true }],
|
||||
])("turns the module's own %i into that page", async (status, expected) => {
|
||||
signedIn()
|
||||
mocks.load.mockRejectedValue(refusal(status))
|
||||
const error = (await thrown(workspacePageData(params, request()))) as { data?: unknown }
|
||||
expect(isNotFound(error)).toBe(true)
|
||||
expect(error.data).toEqual(expected)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user