Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.
Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.
Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.
Expected source tree: 0a4a7528e9.
113 lines
7.0 KiB
JavaScript
113 lines
7.0 KiB
JavaScript
import assert from "node:assert/strict"
|
|
import { readFile } from "node:fs/promises"
|
|
import test from "node:test"
|
|
import vm from "node:vm"
|
|
import ts from "typescript"
|
|
|
|
async function compile(path, imports) {
|
|
const source = await readFile(new URL(path, import.meta.url), "utf8")
|
|
const compiled = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX } })
|
|
const loaded = { exports: {} }
|
|
vm.runInNewContext(compiled.outputText, { exports: loaded.exports, module: loaded, Intl, Date, Set, AbortController, setTimeout, clearTimeout, require: name => { assert.ok(name in imports, `unexpected import ${name}`); return imports[name] } })
|
|
return loaded.exports
|
|
}
|
|
const helpers = await compile("../../lib/support-availability.ts", {})
|
|
const enums = await compile("../../lib/generated/enums.ts", {})
|
|
const mappings = await compile("../../lib/support-availability-i18n.ts", { "@/lib/generated/enums": enums })
|
|
const guard = await compile("../../lib/session-request-guard.ts", {})
|
|
const sessionA = { user: { id: 1 }, accessToken: "fixture-a" }
|
|
const sessionB = { user: { id: 2 }, accessToken: "fixture-b" }
|
|
const calendar = { teamId: 5, mode: "recurring", timezone: "UTC", effectiveTimezone: "UTC", deploymentTimezone: "UTC", weekly: [], exceptions: [] }
|
|
const operator = { userId: 1, serviceStatus: 1, effectiveServiceStatus: 1, returnServiceStatus: 0, reason: "busy", online: true, calendar }
|
|
function deferred() { let resolve; const promise = new Promise(r => { resolve = r }); return { promise, resolve } }
|
|
function find(node, predicate) {
|
|
if (!node || typeof node !== "object") return null
|
|
if (predicate(node)) return node
|
|
for (const value of Object.values(node.props ?? {})) {
|
|
for (const child of Array.isArray(value) ? value.flat(Infinity) : [value]) {
|
|
const found = find(child, predicate)
|
|
if (found) return found
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
async function harness(kind, options = {}) {
|
|
let session = sessionA, stateIndex = 0
|
|
const effects = [], calls = [], saved = []
|
|
const apiResult = options.apiResult ?? Promise.resolve(operator)
|
|
const formValues = options.formValues ?? { serviceStatus: "1", start: "", end: "", startOccurrence: "", endOccurrence: "" }
|
|
const jsx = (type, props, key) => ({ type, props, key })
|
|
const controls = new Proxy({}, { get: (_target, name) => name })
|
|
const imports = {
|
|
"react/jsx-runtime": { jsx, jsxs: jsx, Fragment: "Fragment" },
|
|
react: { useRef: value => ({ current: value }), useState: value => { const current = stateIndex++; return [current === 0 && options.editing ? true : typeof value === "function" ? value() : value, () => {}] }, useEffect: fn => { effects.push(fn) }, useCallback: fn => fn },
|
|
"react-hook-form": { Controller: "Controller", useFieldArray: () => ({ fields: [] }), useForm: () => ({ control: {}, register: () => ({}), handleSubmit: fn => fn, watch: key => key ? formValues[key] : calendar, setError: () => {}, clearErrors: () => {}, reset: () => {}, formState: { errors: {}, isDirty: true } }) },
|
|
"lucide-react": controls, "next/link": { default: "Link" }, sonner: { toast: { success: () => {} } },
|
|
"@/components/auth-provider": { useAuth: () => ({ session }) },
|
|
"@/components/confirm-provider": { useConfirm: () => options.confirm ?? (async () => true) },
|
|
"@/components/option-combobox": controls, "@/components/project-dialog": controls,
|
|
"@/components/ui/badge": controls, "@/components/ui/button": controls, "@/components/ui/field": controls, "@/components/ui/input": controls, "@/components/ui/switch": controls,
|
|
"@/i18n/provider": { useI18n: () => key => key, useAppLocale: () => ({ locale: "en-US" }) },
|
|
"@/lib/auth": { readSession: () => session }, "@/lib/session-request-guard": guard,
|
|
"@/lib/generated/enums": enums, "@/lib/support-availability-i18n": mappings, "@/lib/support-availability": helpers,
|
|
"@/components/support-availability/operator-status": { notifyAvailabilityUpdated: () => {} },
|
|
"@/lib/api/support-availability": { updateMyAvailability: payload => { calls.push(payload); return apiResult }, updateAgentAvailability: (id, payload) => { calls.push({ id, payload }); return apiResult }, updateSupportCalendar: payload => { calls.push(payload); return options.apiResult ?? Promise.resolve(calendar) } },
|
|
}
|
|
const file = kind === "operator" ? "./operator-status.tsx" : "../../app/(dashboard)/dashboard/support-availability/_components/calendar-editor.tsx"
|
|
const loaded = await compile(file, imports)
|
|
const root = kind === "operator" ? loaded.OperatorStatusDialog({ value: operator, onClose() {}, onSaved: value => saved.push(value) }) : loaded.CalendarEditor({ initial: calendar, writable: options.writable ?? true, onDirtyChange() {}, onSaved: value => saved.push(value) })
|
|
// Execute only lifetime effects: calendar also registers browser navigation listeners.
|
|
const lifetime = effects.filter(fn => fn.toString().includes("mounted.current = true"))
|
|
assert.equal(lifetime.length, 1)
|
|
const setup = () => lifetime[0]()
|
|
const submit = find(root, node => node.type === "form").props.onSubmit
|
|
return { calls, saved, setup, submit: () => submit(kind === "operator" ? formValues : calendar), switchSession: () => { session = sessionB } }
|
|
}
|
|
|
|
test("operator save still completes after StrictMode setup-cleanup-setup", async () => {
|
|
const h = await harness("operator")
|
|
h.setup()(); h.setup()
|
|
await h.submit()
|
|
assert.equal(h.calls.length, 1)
|
|
assert.equal(h.saved.length, 1)
|
|
})
|
|
test("operator save is single-flight and a late prior-session result is ignored", async () => {
|
|
const pending = deferred()
|
|
const h = await harness("operator", { apiResult: pending.promise })
|
|
h.setup()
|
|
const first = h.submit(), second = h.submit()
|
|
h.switchSession(); pending.resolve(operator)
|
|
await Promise.all([first, second])
|
|
assert.equal(h.calls.length, 1)
|
|
assert.equal(h.saved.length, 0)
|
|
})
|
|
test("operator controls from a stale session cannot submit a mutation", async () => {
|
|
const h = await harness("operator")
|
|
h.setup(); h.switchSession(); await h.submit()
|
|
assert.equal(h.calls.length, 0)
|
|
})
|
|
test("read-only calendar or preview Enter cannot save even when form appears dirty", async () => {
|
|
for (const writable of [false, true]) {
|
|
const h = await harness("calendar", { writable })
|
|
h.setup(); await h.submit()
|
|
assert.equal(h.calls.length, 0)
|
|
}
|
|
})
|
|
test("calendar confirmation cannot cross session or unmount boundaries", async () => {
|
|
for (const action of ["session", "unmount"]) {
|
|
const approval = deferred()
|
|
const h = await harness("calendar", { editing: true, confirm: () => approval.promise })
|
|
const cleanup = h.setup()
|
|
const submit = h.submit()
|
|
if (action === "session") h.switchSession(); else cleanup()
|
|
approval.resolve(true); await submit
|
|
assert.equal(h.calls.length, 0)
|
|
}
|
|
})
|
|
test("calendar save completes after StrictMode restart and explicit confirmation", async () => {
|
|
const h = await harness("calendar", { editing: true })
|
|
h.setup()(); h.setup(); await h.submit()
|
|
assert.equal(h.calls.length, 1)
|
|
assert.equal(h.saved.length, 1)
|
|
})
|