-
Notifications
You must be signed in to change notification settings - Fork 110
refactor(ack-pay): extract timestamp schemas #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import * as v from "valibot" | ||
| import { describe, expect, it } from "vitest" | ||
|
|
||
| import { paymentRequestSchema as valibotPaymentRequestSchema } from "./schemas/valibot" | ||
| import { paymentRequestSchema as zodV3PaymentRequestSchema } from "./schemas/zod/v3" | ||
| import { paymentRequestSchema as zodV4PaymentRequestSchema } from "./schemas/zod/v4" | ||
|
|
||
| const paymentRequest = { | ||
| id: "test-payment-request-id", | ||
| paymentOptions: [ | ||
| { | ||
| id: "test-payment-option-id", | ||
| amount: 10, | ||
| decimals: 2, | ||
| currency: "USD", | ||
| recipient: "sol:123", | ||
| }, | ||
| ], | ||
| } | ||
|
|
||
| describe("paymentRequestSchema", () => { | ||
| it("reports invalid expiresAt strings as schema errors", () => { | ||
| const input = { | ||
| ...paymentRequest, | ||
| expiresAt: "invalid-date", | ||
| } | ||
|
|
||
| expect(v.safeParse(valibotPaymentRequestSchema, input).success).toBe(false) | ||
| expect(zodV3PaymentRequestSchema.safeParse(input).success).toBe(false) | ||
| expect(zodV4PaymentRequestSchema.safeParse(input).success).toBe(false) | ||
| }) | ||
|
|
||
| it("normalizes valid expiresAt inputs to an ISO string", () => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename the test to follow the required assertive pattern. Use one of the mandated prefixes (e.g., 🤖 Prompt for AI Agents |
||
| const expected = "2024-12-31T23:59:59.000Z" | ||
| for (const expiresAt of [ | ||
| new Date("2024-12-31T23:59:59Z"), | ||
| "2024-12-31T23:59:59Z", | ||
| ]) { | ||
| const input = { ...paymentRequest, expiresAt } | ||
|
|
||
| const valibot = v.safeParse(valibotPaymentRequestSchema, input) | ||
| expect(valibot.success && valibot.output.expiresAt).toBe(expected) | ||
|
|
||
| const v3 = zodV3PaymentRequestSchema.safeParse(input) | ||
| expect(v3.success && v3.data.expiresAt).toBe(expected) | ||
|
|
||
| const v4 = zodV4PaymentRequestSchema.safeParse(input) | ||
| expect(v4.success && v4.data.expiresAt).toBe(expected) | ||
| } | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,12 @@ import * as v from "valibot" | |
|
|
||
| const urlOrDidUri = v.union([v.pipe(v.string(), v.url()), didUriSchema]) | ||
|
|
||
| const timestampSchema = v.pipe( | ||
| v.union([v.date(), v.string()]), | ||
| v.check((input) => !Number.isNaN(new Date(input).getTime()), "Invalid date"), | ||
| v.transform((input) => new Date(input).toISOString()), | ||
| ) | ||
|
coderabbitai[bot] marked this conversation as resolved.
Comment on lines
+7
to
+11
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional: Valibot ships an const timestampSchema = v.pipe(
v.union([v.date(), v.pipe(v.string(), v.isoTimestamp())]),
v.transform((input) => new Date(input).toISOString()),
)Two upsides: it drops the custom Behavioral caveat to decide on first: |
||
|
|
||
| export const paymentOptionSchema = v.object({ | ||
| id: v.string(), | ||
| amount: v.union([v.pipe(v.number(), v.integer(), v.gtValue(0)), v.string()]), | ||
|
|
@@ -19,12 +25,7 @@ export const paymentRequestSchema = v.object({ | |
| id: v.string(), | ||
| description: v.optional(v.string()), | ||
| serviceCallback: v.optional(v.pipe(v.string(), v.url())), | ||
| expiresAt: v.optional( | ||
| v.pipe( | ||
| v.union([v.date(), v.string()]), | ||
| v.transform((input) => new Date(input).toISOString()), | ||
| ), | ||
| ), | ||
| expiresAt: v.optional(timestampSchema), | ||
| paymentOptions: v.pipe( | ||
| v.tupleWithRest([paymentOptionSchema], paymentOptionSchema), | ||
| v.nonEmpty(), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only exercises the rejection path. Please add a happy-path test asserting that valid inputs are accepted and normalized to an ISO string across all three schemas — the
.toISOString()transform is the load-bearing behavior here and is currently only covered indirectly (and only for valibot) bycreate-signed-payment-request.test.ts. A direct parity test guards against the three implementations drifting.Suggested cases (a
Dateobject and an equivalent string, both normalizing to the same ISO output):