Completes the first milestone of The Pet Loft ecommerce platform: - apps/storefront: full customer-facing Next.js app with HeroUI (cart, checkout, orders, wishlist, product detail, shop, search, auth) - convex/: serverless backend with schema, queries, mutations, actions, HTTP routes, Stripe/Shippo integrations, and co-located tests - packages/types, packages/utils, packages/convex: shared workspace packages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
128 lines
5.0 KiB
TypeScript
128 lines
5.0 KiB
TypeScript
import { describe, it, expect, expectTypeOf } from "vitest";
|
|
import type {
|
|
ShippoConfidenceScore,
|
|
ShippoValidationValue,
|
|
ShippoAddressType,
|
|
ShippoValidationReason,
|
|
RecommendedAddress,
|
|
AddressValidationResult,
|
|
} from "./checkout";
|
|
|
|
describe("AddressValidationResult types", () => {
|
|
it("ShippoConfidenceScore accepts valid literals", () => {
|
|
expectTypeOf<"high">().toMatchTypeOf<ShippoConfidenceScore>();
|
|
expectTypeOf<"medium">().toMatchTypeOf<ShippoConfidenceScore>();
|
|
expectTypeOf<"low">().toMatchTypeOf<ShippoConfidenceScore>();
|
|
});
|
|
|
|
it("ShippoValidationValue accepts valid literals", () => {
|
|
expectTypeOf<"valid">().toMatchTypeOf<ShippoValidationValue>();
|
|
expectTypeOf<"partially_valid">().toMatchTypeOf<ShippoValidationValue>();
|
|
expectTypeOf<"invalid">().toMatchTypeOf<ShippoValidationValue>();
|
|
});
|
|
|
|
it("ShippoAddressType accepts valid literals", () => {
|
|
expectTypeOf<"residential">().toMatchTypeOf<ShippoAddressType>();
|
|
expectTypeOf<"commercial">().toMatchTypeOf<ShippoAddressType>();
|
|
expectTypeOf<"unknown">().toMatchTypeOf<ShippoAddressType>();
|
|
expectTypeOf<"po_box">().toMatchTypeOf<ShippoAddressType>();
|
|
expectTypeOf<"military">().toMatchTypeOf<ShippoAddressType>();
|
|
});
|
|
|
|
it("ShippoValidationReason has code and description", () => {
|
|
expectTypeOf<ShippoValidationReason>().toHaveProperty("code");
|
|
expectTypeOf<ShippoValidationReason>().toHaveProperty("description");
|
|
});
|
|
|
|
it("RecommendedAddress has required fields and no state", () => {
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("addressLine1");
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("city");
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("postalCode");
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("country");
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceScore");
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceCode");
|
|
expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceDescription");
|
|
|
|
type Keys = keyof RecommendedAddress;
|
|
expectTypeOf<"state" extends Keys ? true : false>().toEqualTypeOf<false>();
|
|
expectTypeOf<"addressLine2" extends Keys ? true : false>().toEqualTypeOf<false>();
|
|
});
|
|
|
|
it("AddressValidationResult is structurally complete", () => {
|
|
expectTypeOf<AddressValidationResult>().toHaveProperty("isValid");
|
|
expectTypeOf<AddressValidationResult>().toHaveProperty("validationValue");
|
|
expectTypeOf<AddressValidationResult>().toHaveProperty("reasons");
|
|
expectTypeOf<AddressValidationResult>().toHaveProperty("addressType");
|
|
expectTypeOf<AddressValidationResult>().toHaveProperty("changedAttributes");
|
|
expectTypeOf<AddressValidationResult>().toHaveProperty("originalAddress");
|
|
});
|
|
|
|
it("recommendedAddress is optional on AddressValidationResult", () => {
|
|
const withoutRecommended: AddressValidationResult = {
|
|
isValid: true,
|
|
validationValue: "valid",
|
|
reasons: [],
|
|
addressType: "unknown",
|
|
changedAttributes: [],
|
|
originalAddress: {
|
|
addressLine1: "10 Downing Street",
|
|
city: "London",
|
|
postalCode: "SW1A 2AA",
|
|
country: "GB",
|
|
},
|
|
};
|
|
expect(withoutRecommended.recommendedAddress).toBeUndefined();
|
|
});
|
|
|
|
it("AddressValidationResult accepts a full object with recommended address", () => {
|
|
const full: AddressValidationResult = {
|
|
isValid: false,
|
|
validationValue: "partially_valid",
|
|
reasons: [{ code: "postal_data_match", description: "Postal code matched" }],
|
|
addressType: "unknown",
|
|
changedAttributes: ["postalCode"],
|
|
recommendedAddress: {
|
|
addressLine1: "10 Downing Street",
|
|
city: "London",
|
|
postalCode: "SW1A 2AA",
|
|
country: "GB",
|
|
completeAddress: "10 Downing Street;LONDON;SW1A 2AA;UNITED KINGDOM",
|
|
confidenceScore: "high",
|
|
confidenceCode: "postal_data_match",
|
|
confidenceDescription: "Matched via postal data",
|
|
},
|
|
originalAddress: {
|
|
addressLine1: "10 Downing St",
|
|
city: "London",
|
|
postalCode: "SW1A2AA",
|
|
country: "GB",
|
|
},
|
|
};
|
|
expect(full.isValid).toBe(false);
|
|
expect(full.recommendedAddress).toBeDefined();
|
|
expect(full.recommendedAddress!.confidenceScore).toBe("high");
|
|
});
|
|
|
|
it("originalAddress uses additionalInformation instead of addressLine2", () => {
|
|
const result: AddressValidationResult = {
|
|
isValid: true,
|
|
validationValue: "valid",
|
|
reasons: [],
|
|
addressType: "unknown",
|
|
changedAttributes: [],
|
|
originalAddress: {
|
|
addressLine1: "10 Downing Street",
|
|
additionalInformation: "Flat 1",
|
|
city: "London",
|
|
postalCode: "SW1A 2AA",
|
|
country: "GB",
|
|
},
|
|
};
|
|
expect(result.originalAddress.additionalInformation).toBe("Flat 1");
|
|
|
|
type OrigKeys = keyof AddressValidationResult["originalAddress"];
|
|
expectTypeOf<"state" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
|
|
expectTypeOf<"addressLine2" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
|
|
});
|
|
});
|