ConusAI vendor v0.1.0-dev.20261027+9b1131fb
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-dev.20261027+9b1131fb
2026-10-27 18:05:17 +00:00
commit 3102273ec7
538 changed files with 80203 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
// The components' markup, rendered on the server the way a page renders it: what a screen reader and
// a keyboard user get is in the HTML, so the accessibility basics are asserted there -- a name for
// every control, a caption and scoped headers for every table, a status that says what a colour would.
import { buildRegistry } from "@conusai-kit/core"
import { createI18n } from "@conusai-kit/i18n"
import { TransportProvider } from "@conusai-kit/ui"
import { renderToStaticMarkup } from "react-dom/server"
import { describe, expect, it } from "vitest"
import { appModules } from "../../index.js"
import type { NoteView } from "../contract/index.js"
import {
Attachments,
attachmentLabels,
createFormLabels,
DeleteNote,
deleteLabels,
editFormLabels,
listLabels,
NoteForm,
NoteList,
sizeLabel,
} from "../ui/index.js"
const catalogues = buildRegistry([...appModules]).catalogues
const i18n = createI18n("en", { en: { notes: catalogues.en?.notes ?? {} } })
const t = (key: string, values?: Record<string, string | number>) => i18n.message(`notes.${key}`, values)
const slugs = { org: "acme", workspace: "ws", project: "p" }
const failed = "That did not work: {detail}"
const inProvider = (node: React.ReactNode) =>
renderToStaticMarkup(
<TransportProvider call={async () => undefined} describe={() => "x"}>
{node}
</TransportProvider>,
)
const note = (over: Partial<NoteView> = {}): NoteView => ({
noteId: "n1",
title: "Kick-off",
body: "Agenda",
version: 3,
createdBy: "u1",
createdAt: "2026-04-01T08:00:00.000Z",
updatedAt: "2026-04-02T08:00:00.000Z",
attachmentCount: 2,
...over,
})
describe("the note list", () => {
const html = renderToStaticMarkup(
<NoteList
notes={[note(), note({ noteId: "n2", title: "Retro" })]}
hrefFor={(id) => `/acme/ws/p/notes/${id}`}
labels={listLabels(t)}
formatDate={(iso) => iso.slice(0, 10)}
/>,
)
it("is a table with a caption and a scoped header for every column", () => {
expect(html).toContain("<caption>Notes</caption>")
expect(html.match(/<th scope="col">/g)).toHaveLength(3)
expect(html).toContain('<th scope="row">')
})
it("names each link by its note, so a list of links is not a list of the same word", () => {
expect(html).toContain('aria-label="Open Kick-off"')
expect(html).toContain('aria-label="Open Retro"')
expect(html).toContain('href="/acme/ws/p/notes/n1"')
})
it("says so in words when there is nothing to list", () => {
const empty = renderToStaticMarkup(
<NoteList notes={[]} hrefFor={() => ""} labels={listLabels(t)} formatDate={() => ""} />,
)
expect(empty).toBe('<p data-guide="notes.note-list">No notes yet.</p>')
})
})
describe("the note form", () => {
const html = inProvider(
<NoteForm
slugs={slugs}
target={{ mode: "create", listHref: "/acme/ws/p/notes" }}
labels={createFormLabels(t, failed)}
/>,
)
it("labels every field", () => {
for (const name of ["title", "body"]) {
const id = new RegExp(`<(?:input|textarea) [^>]*\\bid="([^"]+)"[^>]*\\bname="${name}"`).exec(html)?.[1]
expect(id, name).toBeTruthy()
expect(html).toMatch(new RegExp(`<label for="${id}">`))
}
})
it("starts empty to create, and carries the note's words to edit", () => {
expect(html).toContain("New note")
const edit = inProvider(
<NoteForm
slugs={slugs}
target={{ mode: "edit", noteId: "n1", version: 3, title: "Kick-off", body: "Agenda" }}
labels={editFormLabels(t, failed)}
/>,
)
expect(edit).toContain("Edit note")
expect(edit).toContain('value="Kick-off"')
expect(edit).toContain(">Agenda</textarea>")
})
it("announces its outcome in a status region", () => {
expect(html).toContain('<p role="status">')
})
})
describe("the attachments", () => {
const render = (enabled: boolean, rows: Parameters<typeof Attachments>[0]["rows"]) =>
inProvider(
<Attachments
slugs={slugs}
noteId="n1"
rows={rows}
enabled={enabled}
accept={["text/plain", "application/pdf"]}
labels={attachmentLabels(t, failed, rows.length)}
/>,
)
const rows = [
{ attachmentId: "a1", fileId: "f1", filename: "minutes.txt", contentType: "text/plain", size: sizeLabel(t, 2048) },
]
it("lists each file in a captioned table and names each remove button by its file", () => {
const html = render(true, rows)
expect(html).toContain("<caption>Attachments</caption>")
expect(html).toContain('<th scope="row">minutes.txt</th>')
expect(html).toContain("2 KB")
expect(html).toContain('aria-label="Remove minutes.txt"')
expect(html).toContain('href="/api/v1/files.file.download?org=acme&amp;workspace=ws&amp;project=p&amp;fileId=f1"')
expect(html).toContain('aria-label="Download minutes.txt"')
expect(html).toContain("1 attachment")
})
it("labels its file input, describes it with the hint, and asks for the types it accepts", () => {
const html = render(true, [])
const id = /<input [^>]*\bid="([^"]+)"[^>]*\bname="file"/.exec(html)?.[1]
expect(id).toBeTruthy()
expect(html).toContain(`<label for="${id}">Attach a file</label>`)
expect(html).toContain("aria-describedby=")
expect(html).toContain('accept="text/plain,application/pdf"')
expect(html).toContain("Nothing is attached.")
})
it("offers no upload when the feature flag is off, and says why", () => {
const html = render(false, [])
expect(html).not.toContain('type="file"')
expect(html).toContain("Attachments are switched off for this project.")
})
})
describe("the delete button", () => {
it("asks first: the destructive button is not on the page until the person has said yes to a question", () => {
const html = inProvider(
<DeleteNote slugs={slugs} noteId="n1" listHref="/acme/ws/p/notes" labels={deleteLabels(t, failed)} />,
)
expect(html).toContain("Delete note")
expect(html).not.toContain("Yes, delete the note")
})
})