Update Prisma and harden tests
This commit is contained in:
parent
a2f9d4bd1a
commit
d8eb38fe52
17 changed files with 171 additions and 119 deletions
22
bun.lock
22
bun.lock
|
|
@ -11,7 +11,7 @@
|
|||
"@hookform/resolvers": "^3.10.0",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@paper-design/shaders-react": "^0.0.55",
|
||||
"@prisma/client": "^6.16.2",
|
||||
"@prisma/client": "^6.19.0",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
|
|
@ -83,7 +83,7 @@
|
|||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"jsdom": "^27.0.1",
|
||||
"playwright": "^1.56.1",
|
||||
"prisma": "^6.16.2",
|
||||
"prisma": "^6.19.0",
|
||||
"tailwindcss": "^4",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tw-animate-css": "^1.3.8",
|
||||
|
|
@ -421,19 +421,19 @@
|
|||
|
||||
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
|
||||
|
||||
"@prisma/client": ["@prisma/client@6.16.3", "", { "optionalDependencies": { "prisma": "6.16.3", "typescript": "5.9.3" } }, "sha512-JfNfAtXG+/lIopsvoZlZiH2k5yNx87mcTS4t9/S5oufM1nKdXYxOvpDC1XoTCFBa5cQh7uXnbMPsmZrwZY80xw=="],
|
||||
"@prisma/client": ["@prisma/client@6.19.0", "", { "peerDependencies": { "prisma": "*", "typescript": ">=5.1.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g=="],
|
||||
|
||||
"@prisma/config": ["@prisma/config@6.16.3", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.16.12", "empathic": "2.0.0" } }, "sha512-VlsLnG4oOuKGGMToEeVaRhoTBZu5H3q51jTQXb/diRags3WV0+BQK5MolJTtP6G7COlzoXmWeS11rNBtvg+qFQ=="],
|
||||
"@prisma/config": ["@prisma/config@6.19.0", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg=="],
|
||||
|
||||
"@prisma/debug": ["@prisma/debug@6.16.3", "", {}, "sha512-89DdqWtdKd7qoc9/qJCKLTazj3W3zPEiz0hc7HfZdpjzm21c7orOUB5oHWJsG+4KbV4cWU5pefq3CuDVYF9vgA=="],
|
||||
"@prisma/debug": ["@prisma/debug@6.19.0", "", {}, "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA=="],
|
||||
|
||||
"@prisma/engines": ["@prisma/engines@6.16.3", "", { "dependencies": { "@prisma/debug": "6.16.3", "@prisma/engines-version": "6.16.1-1.bb420e667c1820a8c05a38023385f6cc7ef8e83a", "@prisma/fetch-engine": "6.16.3", "@prisma/get-platform": "6.16.3" } }, "sha512-b+Rl4nzQDcoqe6RIpSHv8f5lLnwdDGvXhHjGDiokObguAAv/O1KaX1Oc69mBW/GFWKQpCkOraobLjU6s1h8HGg=="],
|
||||
"@prisma/engines": ["@prisma/engines@6.19.0", "", { "dependencies": { "@prisma/debug": "6.19.0", "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", "@prisma/fetch-engine": "6.19.0", "@prisma/get-platform": "6.19.0" } }, "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw=="],
|
||||
|
||||
"@prisma/engines-version": ["@prisma/engines-version@6.16.1-1.bb420e667c1820a8c05a38023385f6cc7ef8e83a", "", {}, "sha512-fftRmosBex48Ph1v2ll1FrPpirwtPZpNkE5CDCY1Lw2SD2ctyrLlVlHiuxDAAlALwWBOkPbAll4+EaqdGuMhJw=="],
|
||||
"@prisma/engines-version": ["@prisma/engines-version@6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", "", {}, "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ=="],
|
||||
|
||||
"@prisma/fetch-engine": ["@prisma/fetch-engine@6.16.3", "", { "dependencies": { "@prisma/debug": "6.16.3", "@prisma/engines-version": "6.16.1-1.bb420e667c1820a8c05a38023385f6cc7ef8e83a", "@prisma/get-platform": "6.16.3" } }, "sha512-bUoRIkVaI+CCaVGrSfcKev0/Mk4ateubqWqGZvQ9uCqFv2ENwWIR3OeNuGin96nZn5+SkebcD7RGgKr/+mJelw=="],
|
||||
"@prisma/fetch-engine": ["@prisma/fetch-engine@6.19.0", "", { "dependencies": { "@prisma/debug": "6.19.0", "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", "@prisma/get-platform": "6.19.0" } }, "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ=="],
|
||||
|
||||
"@prisma/get-platform": ["@prisma/get-platform@6.16.3", "", { "dependencies": { "@prisma/debug": "6.16.3" } }, "sha512-X1LxiFXinJ4iQehrodGp0f66Dv6cDL0GbRlcCoLtSu6f4Wi+hgo7eND/afIs5029GQLgNWKZ46vn8hjyXTsHLA=="],
|
||||
"@prisma/get-platform": ["@prisma/get-platform@6.19.0", "", { "dependencies": { "@prisma/debug": "6.19.0" } }, "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
||||
|
||||
|
|
@ -1121,7 +1121,7 @@
|
|||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"effect": ["effect@3.16.12", "", { "dependencies": { "@standard-schema/spec": "1.0.0", "fast-check": "3.23.2" } }, "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg=="],
|
||||
"effect": ["effect@3.18.4", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.234", "", {}, "sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg=="],
|
||||
|
||||
|
|
@ -1617,7 +1617,7 @@
|
|||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
|
||||
"prisma": ["prisma@6.16.3", "", { "dependencies": { "@prisma/config": "6.16.3", "@prisma/engines": "6.16.3" }, "optionalDependencies": { "typescript": "5.9.3" }, "bin": { "prisma": "build/index.js" } }, "sha512-4tJq3KB9WRshH5+QmzOLV54YMkNlKOtLKaSdvraI5kC/axF47HuOw6zDM8xrxJ6s9o2WodY654On4XKkrobQdQ=="],
|
||||
"prisma": ["prisma@6.19.0", "", { "dependencies": { "@prisma/config": "6.19.0", "@prisma/engines": "6.19.0" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw=="],
|
||||
|
||||
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "1.4.0", "object-assign": "4.1.1", "react-is": "16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const eslintConfig = [
|
|||
"build/**",
|
||||
"apps/desktop/dist/**",
|
||||
"apps/desktop/src-tauri/target/**",
|
||||
"nova-calendar-main/**",
|
||||
"next-env.d.ts",
|
||||
"convex/_generated/**",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
"@hookform/resolvers": "^3.10.0",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@paper-design/shaders-react": "^0.0.55",
|
||||
"@prisma/client": "^6.16.2",
|
||||
"@prisma/client": "^6.19.0",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"jsdom": "^27.0.1",
|
||||
"playwright": "^1.56.1",
|
||||
"prisma": "^6.16.2",
|
||||
"prisma": "^6.19.0",
|
||||
"tailwindcss": "^4",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tw-animate-css": "^1.3.8",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ vi.mock("@/server/convex-client", () => {
|
|||
})
|
||||
|
||||
const mockCookieStore = {
|
||||
get: vi.fn<() => unknown, []>(),
|
||||
get: vi.fn<() => unknown>(),
|
||||
}
|
||||
|
||||
vi.mock("next/headers", () => ({
|
||||
|
|
|
|||
|
|
@ -92,7 +92,10 @@ export const { signIn, signOut, useSession } = authClient
|
|||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const devBypass = process.env.NODE_ENV !== "production" && process.env.NEXT_PUBLIC_DEV_BYPASS_AUTH === "1"
|
||||
const { data: baseSession, isPending } = useSession()
|
||||
const session: AppSession | null = baseSession ?? (devBypass
|
||||
const session = useMemo<AppSession | null>(
|
||||
() =>
|
||||
baseSession ??
|
||||
(devBypass
|
||||
? {
|
||||
session: { id: "dev-session", expiresAt: Date.now() + 1000 * 60 * 60 },
|
||||
user: {
|
||||
|
|
@ -105,7 +108,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||
machinePersona: null,
|
||||
},
|
||||
}
|
||||
: null)
|
||||
: null),
|
||||
[baseSession, devBypass]
|
||||
)
|
||||
const ensureUser = useMutation(api.users.ensureUser)
|
||||
const [convexUserId, setConvexUserId] = useState<string | null>(null)
|
||||
const [machineContext, setMachineContext] = useState<MachineContext | null>(null)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,5 @@ if (process.env.NODE_ENV !== "production") {
|
|||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
// Helps detect mismatched DB path during dev server bootstrap
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("[prisma] Using database:", resolvedDatabaseUrl)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import { toast } from "sonner"
|
|||
|
||||
const METHODS = ["success", "error", "info", "warning", "message", "loading"] as const
|
||||
const TRAILING_PUNCTUATION_REGEX = /[\s!?.…,;:]+$/u
|
||||
const toastAny = toast as unknown as Record<string, (...args: any[]) => unknown> & { __punctuationPatched?: boolean }
|
||||
const toastAny = toast as typeof toast & { __punctuationPatched?: boolean }
|
||||
type ToastMethodKey = (typeof METHODS)[number]
|
||||
|
||||
function stripTrailingPunctuation(value: string): string {
|
||||
const trimmed = value.trimEnd()
|
||||
|
|
@ -19,49 +20,50 @@ function sanitizeContent<T>(value: T): T {
|
|||
return value
|
||||
}
|
||||
|
||||
function sanitizeOptions(options: unknown): unknown {
|
||||
function sanitizeOptions<T>(options: T): T {
|
||||
if (!options || typeof options !== "object") return options
|
||||
if ("description" in options && typeof (options as { description?: unknown }).description === "string") {
|
||||
return {
|
||||
...(options as Record<string, unknown>),
|
||||
description: stripTrailingPunctuation((options as { description: string }).description),
|
||||
}
|
||||
} as T
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
function wrapSimpleMethod(method: (typeof METHODS)[number]) {
|
||||
const original = toastAny[method]
|
||||
function wrapSimpleMethod<K extends ToastMethodKey>(method: K) {
|
||||
const original = toastAny[method] as typeof toast[K]
|
||||
if (typeof original !== "function") return
|
||||
toastAny[method] = (message: unknown, options?: unknown, ...rest: unknown[]) => {
|
||||
return original(sanitizeContent(message), sanitizeOptions(options), ...rest)
|
||||
const patched = ((...args: Parameters<typeof toast[K]>) => {
|
||||
const nextArgs = args.slice() as Parameters<typeof toast[K]>
|
||||
if (nextArgs.length > 0) {
|
||||
nextArgs[0] = sanitizeContent(nextArgs[0])
|
||||
}
|
||||
if (nextArgs.length > 1) {
|
||||
nextArgs[1] = sanitizeOptions(nextArgs[1])
|
||||
}
|
||||
return original.apply(null, nextArgs as Parameters<typeof toast[K]>)
|
||||
}) as typeof toast[K]
|
||||
toastAny[method] = patched
|
||||
}
|
||||
|
||||
function wrapPromise() {
|
||||
const originalPromise = toastAny.promise
|
||||
if (typeof originalPromise !== "function") return
|
||||
toastAny.promise = (promise: Promise<unknown>, messages: Record<string, unknown>, options?: unknown) => {
|
||||
const wrapMessage = (value: unknown) => {
|
||||
if (typeof value === "function") {
|
||||
return (...args: unknown[]) => sanitizeContent((value as (...args: unknown[]) => unknown)(...args))
|
||||
}
|
||||
return sanitizeContent(value)
|
||||
}
|
||||
|
||||
toastAny.promise = ((promise, messages) => {
|
||||
const normalizedMessages =
|
||||
messages && typeof messages === "object"
|
||||
? {
|
||||
? ({
|
||||
...messages,
|
||||
loading: wrapMessage(messages.loading),
|
||||
success: wrapMessage(messages.success),
|
||||
error: wrapMessage(messages.error),
|
||||
finally: wrapMessage((messages as { finally?: unknown }).finally),
|
||||
}
|
||||
loading: sanitizeContent(messages.loading),
|
||||
success: sanitizeContent(messages.success),
|
||||
error: sanitizeContent(messages.error),
|
||||
description: sanitizeContent(messages.description),
|
||||
} satisfies typeof messages)
|
||||
: messages
|
||||
|
||||
return originalPromise(promise, normalizedMessages, sanitizeOptions(options))
|
||||
}
|
||||
return originalPromise(promise, normalizedMessages)
|
||||
}) as typeof toast.promise
|
||||
}
|
||||
|
||||
if (!toastAny.__punctuationPatched) {
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ describe("convex.machines.listTicketsHistory", () => {
|
|||
})
|
||||
|
||||
expect(result.page).toHaveLength(1)
|
||||
expect(result.page[0].id).toBe("ticket_match")
|
||||
expect(result.page[0].id).toBe("ticket_match" as Id<"tickets">)
|
||||
expect(result.isDone).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ describe("convex.reports.backlogOverview", () => {
|
|||
})
|
||||
|
||||
expect(result.rangeDays).toBe(7)
|
||||
expect(result.statusCounts).toEqual({
|
||||
expect(result.statusCounts).toMatchObject({
|
||||
PENDING: 1,
|
||||
PAUSED: 1,
|
||||
RESOLVED: 1,
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ describe("convex.reports.csatOverview", () => {
|
|||
expect(result.averageScore).toBe(4)
|
||||
expect(result.distribution.find((entry) => entry.score === 5)?.total).toBe(1)
|
||||
expect(result.distribution.find((entry) => entry.score === 3)?.total).toBe(1)
|
||||
expect(result.recent[0]?.ticketId).toBe("ticket_a")
|
||||
expect(result.recent[0]?.ticketId).toBe("ticket_a" as Id<"tickets">)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ process.env.BETTER_AUTH_URL ??= process.env.NEXT_PUBLIC_APP_URL
|
|||
const OriginalDate = Date
|
||||
let fixedTimestamp: number | null = null
|
||||
|
||||
type MutableVi = typeof vi & {
|
||||
mocked?: <T>(item: T) => T
|
||||
setSystemTime?: (value: number | Date) => void
|
||||
useFakeTimers?: (...args: Array<unknown>) => void
|
||||
useRealTimers?: (...args: Array<unknown>) => void
|
||||
type ExtendedVi = typeof vi & {
|
||||
mocked?: typeof vi.mocked
|
||||
setSystemTime?: typeof vi.setSystemTime
|
||||
useFakeTimers?: typeof vi.useFakeTimers
|
||||
useRealTimers?: typeof vi.useRealTimers
|
||||
}
|
||||
|
||||
const viExtended = vi as MutableVi
|
||||
const viExtended = vi as ExtendedVi
|
||||
|
||||
if (typeof window === "undefined" || typeof document === "undefined") {
|
||||
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
|
||||
|
|
@ -57,40 +57,48 @@ const applyFixedDate = () => {
|
|||
}
|
||||
|
||||
if (!viExtended.mocked) {
|
||||
viExtended.mocked = <T>(item: T) => item
|
||||
viExtended.mocked = ((item: unknown) => item) as typeof vi.mocked
|
||||
}
|
||||
|
||||
if (!viExtended.setSystemTime) {
|
||||
viExtended.setSystemTime = (value: number | Date) => {
|
||||
fixedTimestamp = typeof value === "number" ? value : value.getTime()
|
||||
applyFixedDate()
|
||||
viExtended.setSystemTime = ((value: string | number | Date) => {
|
||||
if (typeof value === "string") {
|
||||
const parsed = Date.parse(value)
|
||||
fixedTimestamp = Number.isFinite(parsed) ? parsed : Date.now()
|
||||
} else {
|
||||
fixedTimestamp = value instanceof Date ? value.getTime() : value
|
||||
}
|
||||
applyFixedDate()
|
||||
return viExtended
|
||||
}) as typeof vi.setSystemTime
|
||||
}
|
||||
|
||||
if (!viExtended.useFakeTimers) {
|
||||
viExtended.useFakeTimers = () => {
|
||||
// Bun's fake timers are not required for our current tests. This is a noop
|
||||
// placeholder to keep compatibility with the previous Vitest API.
|
||||
}
|
||||
viExtended.useFakeTimers = ((..._args: Parameters<typeof vi.useFakeTimers>) => {
|
||||
return viExtended
|
||||
}) as typeof vi.useFakeTimers
|
||||
} else {
|
||||
const originalUseFakeTimers = viExtended.useFakeTimers.bind(vi)
|
||||
viExtended.useFakeTimers = (...args: Array<unknown>) => {
|
||||
originalUseFakeTimers(...args)
|
||||
}
|
||||
viExtended.useFakeTimers = ((...args: Parameters<typeof vi.useFakeTimers>) => {
|
||||
const result = originalUseFakeTimers(...args)
|
||||
return result ?? viExtended
|
||||
}) as typeof vi.useFakeTimers
|
||||
}
|
||||
|
||||
if (!viExtended.useRealTimers) {
|
||||
viExtended.useRealTimers = () => {
|
||||
viExtended.useRealTimers = ((..._args: Parameters<typeof vi.useRealTimers>) => {
|
||||
fixedTimestamp = null
|
||||
applyFixedDate()
|
||||
}
|
||||
return viExtended
|
||||
}) as typeof vi.useRealTimers
|
||||
} else {
|
||||
const originalUseRealTimers = viExtended.useRealTimers.bind(vi)
|
||||
viExtended.useRealTimers = (...args: Array<unknown>) => {
|
||||
originalUseRealTimers(...args)
|
||||
viExtended.useRealTimers = ((...args: Parameters<typeof vi.useRealTimers>) => {
|
||||
const result = originalUseRealTimers(...args)
|
||||
fixedTimestamp = null
|
||||
applyFixedDate()
|
||||
}
|
||||
return result ?? viExtended
|
||||
}) as typeof vi.useRealTimers
|
||||
}
|
||||
|
||||
applyFixedDate()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { describe, expect, it, vi } from "bun:test"
|
||||
|
||||
import { buildCommentAuthorSummary } from "../convex/tickets"
|
||||
import type { Doc, Id } from "../convex/_generated/dataModel"
|
||||
import type { Doc, Id, TableNames } from "../convex/_generated/dataModel"
|
||||
|
||||
function makeId<TableName extends string>(value: string) {
|
||||
return value as unknown as Id<TableName>
|
||||
function makeId<TableName extends TableNames>(value: string) {
|
||||
return value as Id<TableName>
|
||||
}
|
||||
|
||||
function makeComment(overrides: Partial<Doc<"ticketComments">> = {}) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { describe, expect, it } from "bun:test"
|
|||
|
||||
import { normalizeCustomFieldInputs } from "../src/lib/ticket-form-helpers"
|
||||
import type { TicketFormFieldDefinition } from "../src/lib/ticket-form-types"
|
||||
import type { Id } from "../convex/_generated/dataModel"
|
||||
|
||||
describe("ticket form helpers", () => {
|
||||
const baseFields: TicketFormFieldDefinition[] = [
|
||||
|
|
@ -56,9 +57,9 @@ describe("ticket form helpers", () => {
|
|||
expect(result.ok).toBe(true)
|
||||
if (result.ok) {
|
||||
expect(result.payload).toEqual([
|
||||
{ fieldId: "field-nome", value: "Ana Silva" },
|
||||
{ fieldId: "field-numero", value: 123 },
|
||||
{ fieldId: "field-select", value: "nova" },
|
||||
{ fieldId: "field-nome" as Id<"ticketFields">, value: "Ana Silva" },
|
||||
{ fieldId: "field-numero" as Id<"ticketFields">, value: 123 },
|
||||
{ fieldId: "field-select" as Id<"ticketFields">, value: "nova" },
|
||||
])
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -41,29 +41,28 @@ function buildTicket(overrides: Partial<TicketDoc> = {}): MockedTicket {
|
|||
tenantId: "tenant-1",
|
||||
reference: 41_000,
|
||||
subject: "Computador não liga",
|
||||
summary: null,
|
||||
summary: undefined,
|
||||
status: "AWAITING_ATTENDANCE",
|
||||
priority: "MEDIUM",
|
||||
channel: "EMAIL",
|
||||
queueId: null,
|
||||
queueSnapshot: null,
|
||||
queueId: undefined,
|
||||
requesterId: "user_requester" as Id<"users">,
|
||||
requesterSnapshot: { name: "Cliente", email: "cliente@example.com" },
|
||||
assigneeId: "user_agent" as Id<"users">,
|
||||
assigneeSnapshot: { name: "Agente", email: "agente@example.com" },
|
||||
companyId: null,
|
||||
companySnapshot: null,
|
||||
machineId: null,
|
||||
machineSnapshot: null,
|
||||
slaPolicyId: null,
|
||||
dueAt: null,
|
||||
firstResponseAt: null,
|
||||
resolvedAt: null,
|
||||
companyId: undefined,
|
||||
companySnapshot: undefined,
|
||||
machineId: undefined,
|
||||
machineSnapshot: undefined,
|
||||
slaPolicyId: undefined,
|
||||
dueAt: undefined,
|
||||
firstResponseAt: undefined,
|
||||
resolvedAt: undefined,
|
||||
createdAt: NOW - 50_000,
|
||||
updatedAt: NOW - 1_000,
|
||||
tags: [],
|
||||
customFields: [],
|
||||
activeSessionId: null,
|
||||
activeSessionId: undefined,
|
||||
totalWorkedMs: 0,
|
||||
internalWorkedMs: 0,
|
||||
externalWorkedMs: 0,
|
||||
|
|
@ -74,15 +73,12 @@ function buildTicket(overrides: Partial<TicketDoc> = {}): MockedTicket {
|
|||
csatRatedBy: undefined,
|
||||
csatAssigneeId: undefined,
|
||||
csatAssigneeSnapshot: undefined,
|
||||
workSummary: undefined,
|
||||
reopenDeadline: undefined,
|
||||
reopenedAt: undefined,
|
||||
formTemplate: undefined,
|
||||
chatEnabled: true,
|
||||
relatedTicketIds: undefined,
|
||||
resolvedWithTicketId: undefined,
|
||||
reopenWindowDays: undefined,
|
||||
reopenedBy: undefined,
|
||||
}
|
||||
return { ...(base as TicketDoc), ...overrides }
|
||||
}
|
||||
|
|
@ -149,8 +145,12 @@ describe("convex.tickets.resolveTicketHandler", () => {
|
|||
mockedRequireStaff.mockResolvedValue({
|
||||
user: {
|
||||
_id: "user_agent" as Id<"users">,
|
||||
_creationTime: NOW - 5_000,
|
||||
tenantId: "tenant-1",
|
||||
name: "Agente",
|
||||
email: "agente@example.com",
|
||||
role: "ADMIN",
|
||||
teams: [],
|
||||
},
|
||||
role: "ADMIN",
|
||||
})
|
||||
|
|
@ -214,8 +214,13 @@ describe("convex.tickets.reopenTicketHandler", () => {
|
|||
mockedRequireUser.mockResolvedValue({
|
||||
user: {
|
||||
_id: ticket.requesterId,
|
||||
_creationTime: NOW - 20_000,
|
||||
tenantId: "tenant-1",
|
||||
email: "cliente@example.com",
|
||||
companyId: null,
|
||||
name: "Cliente",
|
||||
role: "COLLABORATOR",
|
||||
companyId: undefined,
|
||||
teams: [],
|
||||
},
|
||||
role: "COLLABORATOR",
|
||||
})
|
||||
|
|
@ -247,8 +252,13 @@ describe("convex.tickets.reopenTicketHandler", () => {
|
|||
mockedRequireUser.mockResolvedValue({
|
||||
user: {
|
||||
_id: ticket.requesterId,
|
||||
_creationTime: NOW - 25_000,
|
||||
tenantId: "tenant-1",
|
||||
email: "cliente@example.com",
|
||||
companyId: null,
|
||||
name: "Cliente",
|
||||
role: "COLLABORATOR",
|
||||
companyId: undefined,
|
||||
teams: [],
|
||||
},
|
||||
role: "COLLABORATOR",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -23,29 +23,28 @@ function makeTicket(overrides: Partial<Doc<"tickets">> = {}): Doc<"tickets"> {
|
|||
tenantId: "tenant-1",
|
||||
reference: 42_100,
|
||||
subject: "Computador não liga",
|
||||
summary: null,
|
||||
summary: undefined,
|
||||
status: "RESOLVED",
|
||||
priority: "MEDIUM",
|
||||
channel: "EMAIL",
|
||||
queueId: null,
|
||||
queueSnapshot: null,
|
||||
queueId: undefined,
|
||||
requesterId: "user_requester" as Id<"users">,
|
||||
requesterSnapshot: { name: "Cliente", email: "cliente@example.com" },
|
||||
assigneeId: null,
|
||||
assigneeSnapshot: null,
|
||||
companyId: null,
|
||||
companySnapshot: null,
|
||||
machineId: null,
|
||||
machineSnapshot: null,
|
||||
slaPolicyId: null,
|
||||
dueAt: null,
|
||||
firstResponseAt: null,
|
||||
assigneeId: undefined,
|
||||
assigneeSnapshot: undefined,
|
||||
companyId: undefined,
|
||||
companySnapshot: undefined,
|
||||
machineId: undefined,
|
||||
machineSnapshot: undefined,
|
||||
slaPolicyId: undefined,
|
||||
dueAt: undefined,
|
||||
firstResponseAt: undefined,
|
||||
resolvedAt: FIXED_NOW - 1000,
|
||||
createdAt: FIXED_NOW - 20_000,
|
||||
updatedAt: FIXED_NOW - 100,
|
||||
tags: [],
|
||||
customFields: [],
|
||||
activeSessionId: null,
|
||||
activeSessionId: undefined,
|
||||
totalWorkedMs: 0,
|
||||
internalWorkedMs: 0,
|
||||
externalWorkedMs: 0,
|
||||
|
|
@ -103,8 +102,13 @@ describe("convex.tickets.submitCsat", () => {
|
|||
mockedRequireUser.mockResolvedValue({
|
||||
user: {
|
||||
_id: "user_requester" as Id<"users">,
|
||||
_creationTime: FIXED_NOW - 30_000,
|
||||
tenantId: "tenant-1",
|
||||
name: "Cliente",
|
||||
email: "cliente@example.com",
|
||||
companyId: null,
|
||||
role: "COLLABORATOR",
|
||||
companyId: undefined,
|
||||
teams: [],
|
||||
},
|
||||
role: "COLLABORATOR",
|
||||
})
|
||||
|
|
@ -145,8 +149,13 @@ describe("convex.tickets.submitCsat", () => {
|
|||
mockedRequireUser.mockResolvedValue({
|
||||
user: {
|
||||
_id: "user_requester" as Id<"users">,
|
||||
_creationTime: FIXED_NOW - 30_000,
|
||||
tenantId: "tenant-1",
|
||||
name: "Cliente",
|
||||
email: "cliente@example.com",
|
||||
companyId: null,
|
||||
role: "COLLABORATOR",
|
||||
companyId: undefined,
|
||||
teams: [],
|
||||
},
|
||||
role: "COLLABORATOR",
|
||||
})
|
||||
|
|
@ -174,8 +183,13 @@ describe("convex.tickets.submitCsat", () => {
|
|||
mockedRequireUser.mockResolvedValue({
|
||||
user: {
|
||||
_id: "user_requester" as Id<"users">,
|
||||
_creationTime: FIXED_NOW - 30_000,
|
||||
tenantId: "tenant-1",
|
||||
name: "Cliente",
|
||||
email: "cliente@example.com",
|
||||
companyId: null,
|
||||
role: "COLLABORATOR",
|
||||
companyId: undefined,
|
||||
teams: [],
|
||||
},
|
||||
role: "COLLABORATOR",
|
||||
})
|
||||
|
|
@ -199,8 +213,13 @@ describe("convex.tickets.submitCsat", () => {
|
|||
mockedRequireUser.mockResolvedValue({
|
||||
user: {
|
||||
_id: "user_admin" as Id<"users">,
|
||||
_creationTime: FIXED_NOW - 40_000,
|
||||
tenantId: "tenant-1",
|
||||
name: "Administrador",
|
||||
email: "admin@example.com",
|
||||
companyId: null,
|
||||
role: "ADMIN",
|
||||
companyId: undefined,
|
||||
teams: [],
|
||||
},
|
||||
role: "ADMIN",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -35,11 +35,13 @@
|
|||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.d.ts",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"apps/desktop/**"
|
||||
"apps/desktop/**",
|
||||
"nova-calendar-main/**"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
5
types/bun-test-vi.d.ts
vendored
Normal file
5
types/bun-test-vi.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
type VitestVi = typeof import("vitest")["vi"]
|
||||
|
||||
declare module "bun:test" {
|
||||
export const vi: VitestVi
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue