@thorprovider/blocks 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -0
- package/README.md +108 -23
- package/docs/standards/data-contracts.md +13 -2
- package/package.json +26 -10
- package/scripts/fix-esm-extensions.mjs +40 -0
- package/src/blocks/e-commerce/navigation/back-to-top.test.tsx +27 -0
- package/src/blocks/e-commerce/navigation/back-to-top.tsx +71 -0
- package/src/blocks/e-commerce/navigation/breadcrumb.test.tsx +174 -0
- package/src/blocks/e-commerce/navigation/breadcrumb.tsx +130 -0
- package/src/blocks/e-commerce/navigation/mobile-bottom-nav.test.tsx +74 -0
- package/src/blocks/e-commerce/navigation/mobile-bottom-nav.tsx +78 -0
- package/src/blocks/e-commerce/navigation/skip-to-content.test.tsx +35 -0
- package/src/blocks/e-commerce/navigation/skip-to-content.tsx +37 -0
- package/src/blocks/e-commerce/product-categories/category-card-grid.test.tsx +122 -0
- package/src/blocks/e-commerce/product-categories/category-card.test.tsx +68 -0
- package/src/blocks/e-commerce/product-categories/category-card.tsx +172 -0
- package/src/blocks/e-commerce/product-categories/category-grid.test.tsx +67 -0
- package/src/blocks/e-commerce/product-categories/category-shared.tsx +109 -0
- package/src/blocks/e-commerce/product-categories/product-category-grid.tsx +170 -0
- package/src/blocks/e-commerce/product-categories/product-category.test.tsx +266 -0
- package/src/blocks/e-commerce/product-categories/product-category.tsx +462 -0
- package/src/blocks/e-commerce/product-list/product-card.test.tsx +263 -0
- package/src/blocks/e-commerce/product-list/product-card.tsx +424 -0
- package/src/blocks/e-commerce/product-list/product-grid.test.tsx +162 -0
- package/src/blocks/e-commerce/product-list/product-grid.tsx +114 -0
- package/src/blocks/e-commerce/product-list/product-showcase-1.test.tsx +78 -0
- package/src/blocks/e-commerce/product-list/product-showcase-1.tsx +277 -0
- package/src/blocks/e-commerce/product-overview/product-overview-gallery.tsx +71 -0
- package/src/blocks/e-commerce/product-overview/{product-overview-5-lightbox-tab.tsx → product-overview-lightbox-tab.tsx} +35 -23
- package/src/blocks/e-commerce/product-overview/{product-overview-5-reviews-tab.tsx → product-overview-reviews-tab.tsx} +40 -17
- package/src/blocks/e-commerce/product-overview/{product-overview-5-tabs.tsx → product-overview-tabs.tsx} +8 -7
- package/src/blocks/e-commerce/product-overview/product-overview.test.tsx +283 -0
- package/src/blocks/e-commerce/product-overview/product-overview.tsx +1186 -0
- package/src/blocks/e-commerce/reviews/review-rating-2.tsx +5 -6
- package/src/blocks/e-commerce/shopping-carts/shopping-cart.test.tsx +399 -0
- package/src/blocks/e-commerce/shopping-carts/{shopping-cart-4.tsx → shopping-cart.tsx} +204 -109
- package/src/blocks/e-commerce/storefront-hero/storefront-hero.test.tsx +412 -0
- package/src/blocks/e-commerce/storefront-hero/storefront-hero.tsx +1283 -0
- package/src/blocks/marketing/features/feature.test.tsx +153 -0
- package/src/blocks/marketing/features/feature.tsx +195 -0
- package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +56 -0
- package/src/blocks/marketing/navbars/navbar-4-account-menu.tsx +30 -14
- package/src/blocks/marketing/navbars/navbar-4-cart-sheet.test.tsx +150 -0
- package/src/blocks/marketing/navbars/navbar-4-cart-sheet.tsx +102 -9
- package/src/blocks/marketing/navbars/navbar-4.test.tsx +154 -2
- package/src/blocks/marketing/navbars/navbar-4.tsx +152 -32
- package/src/index.ts +93 -46
- package/src/lib/contracts-curated.test.ts +42 -24
- package/src/lib/contracts.test.ts +143 -2
- package/src/lib/contracts.ts +395 -13
- package/src/ui/button-group.tsx +1 -1
- package/src/ui/carousel.tsx +1 -1
- package/src/ui/dialog.tsx +1 -1
- package/src/ui/field.tsx +2 -2
- package/src/ui/input-group.tsx +3 -3
- package/src/ui/pagination.tsx +1 -1
- package/src/ui/sidebar.tsx +7 -7
- package/src/ui/toggle-group.tsx +1 -1
- package/tsconfig.build.json +12 -0
- package/tsup.config.ts +11 -7
- package/.turbo/turbo-build.log +0 -24
- package/.turbo/turbo-test.log +0 -37
- package/.turbo/turbo-type-check.log +0 -0
- package/dist/.tsbuildinfo +0 -1
- package/dist/contracts.d.mts +0 -1584
- package/dist/contracts.d.ts +0 -1584
- package/dist/contracts.js +0 -390
- package/dist/contracts.js.map +0 -1
- package/dist/contracts.mjs +0 -334
- package/dist/contracts.mjs.map +0 -1
- package/dist/index.d.mts +0 -2786
- package/dist/index.d.ts +0 -2786
- package/dist/index.js +0 -17139
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -17059
- package/dist/index.mjs.map +0 -1
- package/src/blocks/e-commerce/product-categories/avatar-group.tsx +0 -86
- package/src/blocks/e-commerce/product-categories/product-category-1.tsx +0 -126
- package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +0 -51
- package/src/blocks/e-commerce/product-categories/product-category-2.tsx +0 -120
- package/src/blocks/e-commerce/product-categories/product-category-4.tsx +0 -129
- package/src/blocks/e-commerce/product-categories/product-category-5.tsx +0 -218
- package/src/blocks/e-commerce/product-list/product-card-1.tsx +0 -131
- package/src/blocks/e-commerce/product-list/product-card-2.tsx +0 -71
- package/src/blocks/e-commerce/product-list/product-card-3-reaction-toggle.tsx +0 -166
- package/src/blocks/e-commerce/product-list/product-card-3.tsx +0 -215
- package/src/blocks/e-commerce/product-list/product-card-5-checkbox-check.tsx +0 -98
- package/src/blocks/e-commerce/product-list/product-card-5-reaction-toggle.tsx +0 -171
- package/src/blocks/e-commerce/product-list/product-card-5.tsx +0 -367
- package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +0 -182
- package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +0 -370
- package/src/blocks/e-commerce/product-overview/product-overview-2.tsx +0 -272
- package/src/blocks/e-commerce/product-overview/product-overview-5-gallery.tsx +0 -59
- package/src/blocks/e-commerce/product-overview/product-overview-5.tsx +0 -274
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-1-spinning-counter.tsx +0 -142
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-1.tsx +0 -291
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-item-row.tsx +0 -110
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-recommendations.tsx +0 -51
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-spinning-counter.tsx +0 -146
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2.tsx +0 -295
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-3-spinning-counter.tsx +0 -142
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-3.tsx +0 -342
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4-spinning-counter.tsx +0 -146
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +0 -137
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +0 -65
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +0 -263
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-2.tsx +0 -283
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-5.tsx +0 -318
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-6.tsx +0 -205
- package/src/blocks/marketing/features/feature-1.tsx +0 -97
- package/src/blocks/marketing/features/feature-2.tsx +0 -82
package/src/index.ts
CHANGED
|
@@ -23,16 +23,18 @@ export { default as Navbar4 } from './blocks/marketing/navbars/navbar-4'
|
|
|
23
23
|
export { default as Banner1 } from './blocks/marketing/banners/banner-1'
|
|
24
24
|
export { default as HeroSection1 } from './blocks/marketing/hero-sections/hero-section-1'
|
|
25
25
|
export { default as CtaSection1 } from './blocks/marketing/cta/cta-section-1'
|
|
26
|
-
export { default as
|
|
27
|
-
export { default as Feature2 } from './blocks/marketing/features/feature-2'
|
|
26
|
+
export { default as Feature } from './blocks/marketing/features/feature'
|
|
28
27
|
export { default as Testimonial1 } from './blocks/marketing/testimonials/testimonial-1'
|
|
29
28
|
export { default as Testimonial2 } from './blocks/marketing/testimonials/testimonial-2'
|
|
30
29
|
export { default as FaqBlock1 } from './blocks/marketing/faq/faq-block-1'
|
|
31
30
|
export { default as PricingSection1 } from './blocks/marketing/pricing/pricing-section-1'
|
|
32
31
|
export type { CtaSection1Props } from './blocks/marketing/cta/cta-section-1'
|
|
33
32
|
export type { FaqBlock1Props, FaqItem } from './blocks/marketing/faq/faq-block-1'
|
|
34
|
-
export type {
|
|
35
|
-
|
|
33
|
+
export type {
|
|
34
|
+
FeatureProps,
|
|
35
|
+
FeatureItem,
|
|
36
|
+
FeaturePresentation,
|
|
37
|
+
} from './blocks/marketing/features/feature'
|
|
36
38
|
export type { LogoCloud1Props, LogoCloud1Platform } from './blocks/marketing/logo-clouds/logo-cloud-1'
|
|
37
39
|
export type { PricingSection1Props, PricingTier } from './blocks/marketing/pricing/pricing-section-1'
|
|
38
40
|
export type { Statistic1Props, StatisticItem } from './blocks/marketing/statistics/statistic-1'
|
|
@@ -52,41 +54,57 @@ export type {
|
|
|
52
54
|
FooterSection4SocialIcon,
|
|
53
55
|
FooterSection4SocialLink,
|
|
54
56
|
} from './blocks/marketing/footers/footer-section-4'
|
|
55
|
-
export {
|
|
56
|
-
export {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
export { ProductCard } from './blocks/e-commerce/product-list/product-card'
|
|
58
|
+
export type {
|
|
59
|
+
ProductCardProps,
|
|
60
|
+
ProductCardPresentation,
|
|
61
|
+
} from './blocks/e-commerce/product-list/product-card'
|
|
62
|
+
export { ProductGrid } from './blocks/e-commerce/product-list/product-grid'
|
|
63
|
+
export type { ProductGridProps } from './blocks/e-commerce/product-list/product-grid'
|
|
64
|
+
export { default as ProductShowcase1 } from './blocks/e-commerce/product-list/product-showcase-1'
|
|
65
|
+
export type { ProductShowcase1Props } from './blocks/e-commerce/product-list/product-showcase-1'
|
|
66
|
+
export { default as ProductOverview } from './blocks/e-commerce/product-overview/product-overview'
|
|
67
|
+
export type {
|
|
68
|
+
ProductOverviewProps,
|
|
69
|
+
ProductOverviewRating,
|
|
70
|
+
ProductOverviewPresentation,
|
|
71
|
+
ProductOverviewReview,
|
|
63
72
|
ProductDetailProduct,
|
|
64
73
|
ProductDetailVariant,
|
|
65
|
-
} from './blocks/e-commerce/product-overview/product-overview
|
|
66
|
-
export { default as ProductOverview2 } from './blocks/e-commerce/product-overview/product-overview-2'
|
|
67
|
-
export { default as ProductOverview5 } from './blocks/e-commerce/product-overview/product-overview-5'
|
|
68
|
-
export type { ProductOverview2Props, ProductOverview2Product } from './blocks/e-commerce/product-overview/product-overview-2'
|
|
69
|
-
export type { ProductOverview5Props, ProductOverview5Product, ProductOverview5Review } from './blocks/e-commerce/product-overview/product-overview-5'
|
|
74
|
+
} from './blocks/e-commerce/product-overview/product-overview'
|
|
70
75
|
export { default as ProductQuickView } from './blocks/e-commerce/product-overview/product-quick-view'
|
|
71
76
|
export { default as ReviewRating1 } from './blocks/e-commerce/reviews/review-rating-1'
|
|
72
77
|
export type { ReviewRating1Review } from './blocks/e-commerce/reviews/review-rating-1'
|
|
73
78
|
export { default as ReviewRating2 } from './blocks/e-commerce/reviews/review-rating-2'
|
|
74
|
-
export { default as
|
|
75
|
-
export type {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
} from './blocks/e-commerce/product-categories/
|
|
80
|
-
export {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
export { default as ProductCategory } from './blocks/e-commerce/product-categories/product-category'
|
|
80
|
+
export type {
|
|
81
|
+
ProductCategoryProps,
|
|
82
|
+
ProductCategoryPresentation,
|
|
83
|
+
} from './blocks/e-commerce/product-categories/product-category'
|
|
84
|
+
export { default as CategoryCard } from './blocks/e-commerce/product-categories/category-card'
|
|
85
|
+
export type {
|
|
86
|
+
CategoryCardProps,
|
|
87
|
+
CategoryCardPresentation,
|
|
88
|
+
} from './blocks/e-commerce/product-categories/category-card'
|
|
89
|
+
export { default as CategoryGrid } from './blocks/e-commerce/product-categories/product-category-grid'
|
|
90
|
+
export type {
|
|
91
|
+
CategoryGridProps,
|
|
92
|
+
CategoryGridPresentation,
|
|
93
|
+
} from './blocks/e-commerce/product-categories/product-category-grid'
|
|
84
94
|
export { MegaMenu, megaMenuPropsSchema } from './blocks/e-commerce/navigation/mega-menu'
|
|
85
95
|
export type { MegaMenuProps } from './blocks/e-commerce/navigation/mega-menu'
|
|
86
96
|
export { MobileCategoryDrawer, mobileCategoryDrawerPropsSchema } from './blocks/e-commerce/navigation/mobile-category-drawer'
|
|
87
97
|
export type { MobileCategoryDrawerProps } from './blocks/e-commerce/navigation/mobile-category-drawer'
|
|
88
98
|
export { CategoryIcon, categoryIconNameSchema, categoryIconPropsSchema } from './blocks/e-commerce/navigation/category-icon'
|
|
89
99
|
export type { CategoryIconName, CategoryIconProps } from './blocks/e-commerce/navigation/category-icon'
|
|
100
|
+
export { Breadcrumb, breadcrumbItemSchema, breadcrumbPropsSchema } from './blocks/e-commerce/navigation/breadcrumb'
|
|
101
|
+
export type { BreadcrumbItemData, BreadcrumbProps } from './blocks/e-commerce/navigation/breadcrumb'
|
|
102
|
+
export { SkipToContent, skipToContentPropsSchema } from './blocks/e-commerce/navigation/skip-to-content'
|
|
103
|
+
export type { SkipToContentProps } from './blocks/e-commerce/navigation/skip-to-content'
|
|
104
|
+
export { BackToTop, backToTopPropsSchema, resolveScrollBehavior } from './blocks/e-commerce/navigation/back-to-top'
|
|
105
|
+
export type { BackToTopProps } from './blocks/e-commerce/navigation/back-to-top'
|
|
106
|
+
export { MobileBottomNav, mobileBottomNavItemSchema, mobileBottomNavPropsSchema } from './blocks/e-commerce/navigation/mobile-bottom-nav'
|
|
107
|
+
export type { MobileBottomNavItem, MobileBottomNavProps } from './blocks/e-commerce/navigation/mobile-bottom-nav'
|
|
90
108
|
export { menuItemSchema, collectionItemSchema } from './lib/types/menu'
|
|
91
109
|
export type { MenuItem, CollectionItem } from './lib/types/menu'
|
|
92
110
|
export { default as CategoryFilter1 } from './blocks/e-commerce/category-filters/category-filter-1'
|
|
@@ -114,13 +132,13 @@ export type {
|
|
|
114
132
|
} from './blocks/e-commerce/category-filters/category-filter-2'
|
|
115
133
|
export { default as CategoryFilter4 } from './blocks/e-commerce/category-filters/category-filter-4'
|
|
116
134
|
export type { CategoryFilter4Props, CategoryFilter4Product, CategoryFilter4Facets } from './blocks/e-commerce/category-filters/category-filter-4'
|
|
117
|
-
export { default as
|
|
118
|
-
export {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
export { default as ShoppingCart } from './blocks/e-commerce/shopping-carts/shopping-cart'
|
|
136
|
+
export type {
|
|
137
|
+
ShoppingCartProps,
|
|
138
|
+
ShoppingCartPromotion,
|
|
139
|
+
ShoppingCartPresentation,
|
|
140
|
+
ShoppingCartTotalsState,
|
|
141
|
+
} from './blocks/e-commerce/shopping-carts/shopping-cart'
|
|
124
142
|
export { default as StoreContainer1 } from './blocks/e-commerce/store-containers/store-container-1'
|
|
125
143
|
export type { StoreContainer1Props } from './blocks/e-commerce/store-containers/store-container-1'
|
|
126
144
|
export { default as CheckoutForm1 } from './blocks/e-commerce/checkout-forms/checkout-form-1'
|
|
@@ -167,14 +185,18 @@ export type {
|
|
|
167
185
|
export type { CheckoutFieldError, CheckoutFieldErrors } from './blocks/e-commerce/checkout-forms/checkout-form-types'
|
|
168
186
|
export { default as OrderHistory1 } from './blocks/e-commerce/order-history/order-history-1'
|
|
169
187
|
export { default as OrderHistory2 } from './blocks/e-commerce/order-history/order-history-2'
|
|
170
|
-
export { default as
|
|
188
|
+
export { default as StorefrontHero } from './blocks/e-commerce/storefront-hero/storefront-hero'
|
|
171
189
|
export type {
|
|
172
190
|
FeaturedProduct,
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
191
|
+
HeroImage,
|
|
192
|
+
HeroDepartment,
|
|
193
|
+
HeroFeaturedDeal,
|
|
194
|
+
HeroStoreLocator,
|
|
195
|
+
HeroDeal,
|
|
196
|
+
HeroCategory,
|
|
197
|
+
StorefrontHeroPresentation,
|
|
198
|
+
StorefrontHeroProps,
|
|
199
|
+
} from './blocks/e-commerce/storefront-hero/storefront-hero'
|
|
178
200
|
export { default as AppShell1 } from './blocks/application/app-shells/app-shell-1'
|
|
179
201
|
export { default as LoginPage1 } from './blocks/application/login-forms/login-page-1'
|
|
180
202
|
export { default as LoginPage2 } from './blocks/application/login-forms/login-page-2'
|
|
@@ -201,11 +223,18 @@ export {
|
|
|
201
223
|
cartTotalsSchema,
|
|
202
224
|
productDetailProductSchema,
|
|
203
225
|
productDetailVariantSchema,
|
|
204
|
-
|
|
226
|
+
productOverviewPropsSchema,
|
|
227
|
+
storefrontHeroPropsSchema,
|
|
228
|
+
storefrontHeroProductSchema,
|
|
205
229
|
buttonPropsSchema,
|
|
206
230
|
storeContainer1PropsSchema,
|
|
207
|
-
|
|
208
|
-
|
|
231
|
+
productCardPropsSchema,
|
|
232
|
+
productGridPropsSchema,
|
|
233
|
+
productPresentationSchema,
|
|
234
|
+
productShowcase1PropsSchema,
|
|
235
|
+
shoppingCartPropsSchema,
|
|
236
|
+
shoppingCartItemSchema,
|
|
237
|
+
shoppingCartSuggestionSchema,
|
|
209
238
|
navbar4PropsSchema,
|
|
210
239
|
paymentMethodSchema,
|
|
211
240
|
cardProductSchema,
|
|
@@ -216,16 +245,27 @@ export {
|
|
|
216
245
|
navCartItemSchema,
|
|
217
246
|
storeUserSchema,
|
|
218
247
|
accountMenuItemSchema,
|
|
248
|
+
featurePropsSchema,
|
|
249
|
+
featureCardsSpecSchema,
|
|
250
|
+
featureSplitSpecSchema,
|
|
251
|
+
productCategoryItemSchema,
|
|
252
|
+
productCategoryPropsSchema,
|
|
219
253
|
} from './lib/contracts'
|
|
220
254
|
export type {
|
|
221
255
|
ProductDetailProductSpec,
|
|
222
256
|
ProductDetailVariantSpec,
|
|
223
|
-
|
|
257
|
+
StorefrontHeroProduct,
|
|
258
|
+
StorefrontHeroSpecProps,
|
|
224
259
|
CartTotals,
|
|
225
260
|
ButtonSpecProps,
|
|
226
261
|
StoreContainer1SpecProps,
|
|
227
|
-
|
|
228
|
-
|
|
262
|
+
ProductCardSpecProps,
|
|
263
|
+
ProductGridSpecProps,
|
|
264
|
+
ProductPresentation,
|
|
265
|
+
ProductShowcase1SpecProps,
|
|
266
|
+
ShoppingCartItem,
|
|
267
|
+
ShoppingCartSuggestion,
|
|
268
|
+
ShoppingCartSpecProps,
|
|
229
269
|
Navbar4SpecProps,
|
|
230
270
|
CardProduct,
|
|
231
271
|
CartItem,
|
|
@@ -235,4 +275,11 @@ export type {
|
|
|
235
275
|
NavCartItem,
|
|
236
276
|
StoreUser,
|
|
237
277
|
AccountMenuItem,
|
|
278
|
+
FeatureSpecProps,
|
|
279
|
+
FeatureCardsSpecProps,
|
|
280
|
+
FeatureSplitSpecProps,
|
|
281
|
+
ProductCategoryItem,
|
|
282
|
+
ProductCategorySpecProps,
|
|
283
|
+
CategoryCardSpecProps,
|
|
284
|
+
CategoryGridSpecProps,
|
|
238
285
|
} from './lib/contracts'
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
moneySchema,
|
|
12
12
|
navCartItemSchema,
|
|
13
13
|
navbar4PropsSchema,
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
productOverviewPropsSchema,
|
|
15
|
+
shoppingCartPropsSchema,
|
|
16
16
|
} from './contracts'
|
|
17
17
|
|
|
18
18
|
const product = {
|
|
@@ -55,13 +55,13 @@ describe('moneySchema', () => {
|
|
|
55
55
|
})
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
-
describe('
|
|
58
|
+
describe('productOverviewPropsSchema', () => {
|
|
59
59
|
it('accepts a product whose variant price is omitted or null (unavailable)', () => {
|
|
60
|
-
expect(
|
|
60
|
+
expect(productOverviewPropsSchema.safeParse({ product }).success).toBe(true)
|
|
61
61
|
})
|
|
62
62
|
|
|
63
63
|
it('accepts an explicit controlled selected variant id', () => {
|
|
64
|
-
expect(
|
|
64
|
+
expect(productOverviewPropsSchema.safeParse({ product, selectedVariantId: 'v1' }).success).toBe(true)
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
it('rejects a variant missing selectedOptions', () => {
|
|
@@ -69,7 +69,7 @@ describe('productOverview1PropsSchema', () => {
|
|
|
69
69
|
...product,
|
|
70
70
|
variants: [{ id: 'v1', title: 'x', availableForSale: true, price: null }],
|
|
71
71
|
}
|
|
72
|
-
expect(
|
|
72
|
+
expect(productOverviewPropsSchema.safeParse({ product: bad }).success).toBe(false)
|
|
73
73
|
})
|
|
74
74
|
})
|
|
75
75
|
|
|
@@ -147,24 +147,6 @@ describe('optional brand seams — present, omitted, invalid', () => {
|
|
|
147
147
|
})
|
|
148
148
|
})
|
|
149
149
|
|
|
150
|
-
describe('shoppingCart4PropsSchema — authoritative totals', () => {
|
|
151
|
-
it('accepts backend totals and a controlled totals state', () => {
|
|
152
|
-
const result = shoppingCart4PropsSchema.safeParse({
|
|
153
|
-
items: [],
|
|
154
|
-
totals: {
|
|
155
|
-
subtotal: { amount: '0', currencyCode: 'USD' },
|
|
156
|
-
total: { amount: '0', currencyCode: 'USD' },
|
|
157
|
-
},
|
|
158
|
-
totalsState: 'idle',
|
|
159
|
-
})
|
|
160
|
-
expect(result.success).toBe(true)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('rejects an unknown totals state', () => {
|
|
164
|
-
expect(shoppingCart4PropsSchema.safeParse({ items: [], totalsState: 'loading' }).success).toBe(false)
|
|
165
|
-
})
|
|
166
|
-
})
|
|
167
|
-
|
|
168
150
|
describe('faqBlock1PropsSchema / ctaSection1PropsSchema — bounded editorial sections', () => {
|
|
169
151
|
const faqItem = { value: 'q1', question: '¿Envían a todo el país?', answer: 'Sí.' }
|
|
170
152
|
|
|
@@ -205,3 +187,39 @@ describe('faqBlock1PropsSchema / ctaSection1PropsSchema — bounded editorial se
|
|
|
205
187
|
expect('onPrimaryClick' in parsed).toBe(false)
|
|
206
188
|
})
|
|
207
189
|
})
|
|
190
|
+
|
|
191
|
+
describe('shoppingCartPropsSchema — canonical Money-only cart lines', () => {
|
|
192
|
+
const money = { amount: '22.22', currencyCode: 'USD' }
|
|
193
|
+
|
|
194
|
+
it('accepts a canonical Money line keyed by backend line id', () => {
|
|
195
|
+
const result = shoppingCartPropsSchema.safeParse({
|
|
196
|
+
items: [{ id: 'line_1', name: 'Teclado', quantity: 2, unitPrice: money, lineTotal: money }],
|
|
197
|
+
totals: { subtotal: money, total: money },
|
|
198
|
+
totalsState: 'idle',
|
|
199
|
+
})
|
|
200
|
+
expect(result.success).toBe(true)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('rejects a legacy numeric-price line without canonical Money', () => {
|
|
204
|
+
const result = shoppingCartPropsSchema.safeParse({
|
|
205
|
+
items: [{ id: 'line_1', name: 'Teclado', price: 10, quantity: 2 }],
|
|
206
|
+
})
|
|
207
|
+
expect(result.success).toBe(false)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('rejects an unknown totals state', () => {
|
|
211
|
+
const result = shoppingCartPropsSchema.safeParse({
|
|
212
|
+
items: [],
|
|
213
|
+
totalsState: 'loading',
|
|
214
|
+
})
|
|
215
|
+
expect(result.success).toBe(false)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('omits an absent suggestion image and price honestly', () => {
|
|
219
|
+
const result = shoppingCartPropsSchema.safeParse({
|
|
220
|
+
items: [{ id: 'line_1', name: 'x', quantity: 1, unitPrice: money, lineTotal: money }],
|
|
221
|
+
recentlyViewed: [{ id: 'p1', name: 'Mouse' }],
|
|
222
|
+
})
|
|
223
|
+
expect(result.success).toBe(true)
|
|
224
|
+
})
|
|
225
|
+
})
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import {
|
|
4
|
+
categoryCardPropsSchema,
|
|
5
|
+
categoryGridPropsSchema,
|
|
6
|
+
productCardPropsSchema,
|
|
7
|
+
productGridPropsSchema,
|
|
8
|
+
storeCategorySchema,
|
|
9
|
+
} from './contracts'
|
|
3
10
|
|
|
4
11
|
describe('storeCategorySchema', () => {
|
|
5
12
|
it('accepts flat categories (additive backward compatibility)', () => {
|
|
@@ -29,4 +36,138 @@ describe('storeCategorySchema', () => {
|
|
|
29
36
|
expect(storeCategorySchema.safeParse({ label: 'Solo', href: '/categorias/x', children: [{}] }).success).toBe(false)
|
|
30
37
|
expect(storeCategorySchema.safeParse({}).success).toBe(false)
|
|
31
38
|
})
|
|
32
|
-
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('productCardPropsSchema', () => {
|
|
42
|
+
const canonicalItem = {
|
|
43
|
+
id: 'sku-1',
|
|
44
|
+
title: 'Llave de impacto',
|
|
45
|
+
price: { amount: '129.50', currencyCode: 'EUR' },
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
it('accepts a single canonical Money item with the bounded presentation options', () => {
|
|
49
|
+
expect(productCardPropsSchema.safeParse({ item: canonicalItem }).success).toBe(true)
|
|
50
|
+
expect(
|
|
51
|
+
productCardPropsSchema.safeParse({
|
|
52
|
+
item: canonicalItem,
|
|
53
|
+
presentation: 'classic',
|
|
54
|
+
wishlisted: true,
|
|
55
|
+
}).success,
|
|
56
|
+
).toBe(true)
|
|
57
|
+
expect(
|
|
58
|
+
productCardPropsSchema.safeParse({ item: canonicalItem, presentation: 'rich' }).success,
|
|
59
|
+
).toBe(true)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('rejects a collection in place of the single item', () => {
|
|
63
|
+
expect(productCardPropsSchema.safeParse({ items: [canonicalItem] }).success).toBe(false)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('rejects legacy numeric-price items', () => {
|
|
67
|
+
expect(
|
|
68
|
+
productCardPropsSchema.safeParse({ item: { id: 'p1', title: 'Taladro', price: 49.99, image: '/x.svg' } })
|
|
69
|
+
.success,
|
|
70
|
+
).toBe(false)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('rejects unknown presentation options', () => {
|
|
74
|
+
expect(
|
|
75
|
+
productCardPropsSchema.safeParse({ item: canonicalItem, presentation: 'compact' }).success,
|
|
76
|
+
).toBe(false)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe('productGridPropsSchema', () => {
|
|
81
|
+
const canonicalItem = {
|
|
82
|
+
id: 'sku-1',
|
|
83
|
+
title: 'Llave de impacto',
|
|
84
|
+
price: { amount: '129.50', currencyCode: 'EUR' },
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
it('accepts a collection with the listing state options', () => {
|
|
88
|
+
expect(productGridPropsSchema.safeParse({ items: [canonicalItem] }).success).toBe(true)
|
|
89
|
+
expect(
|
|
90
|
+
productGridPropsSchema.safeParse({
|
|
91
|
+
items: [canonicalItem],
|
|
92
|
+
presentation: 'minimal',
|
|
93
|
+
heading: 'Destacados',
|
|
94
|
+
maxItems: 6,
|
|
95
|
+
wishlistedIds: ['sku-1'],
|
|
96
|
+
loading: false,
|
|
97
|
+
skeletonCount: 6,
|
|
98
|
+
emptyLabel: 'Sin productos',
|
|
99
|
+
}).success,
|
|
100
|
+
).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('declares only serializable keys — no callbacks or label strings', () => {
|
|
104
|
+
const runtimeOnlyKeys = [
|
|
105
|
+
'onAddToCart',
|
|
106
|
+
'onProductClick',
|
|
107
|
+
'onToggleWishlist',
|
|
108
|
+
'onViewSimilar',
|
|
109
|
+
'addToCartLabel',
|
|
110
|
+
'unavailablePriceLabel',
|
|
111
|
+
'addToWishlistLabel',
|
|
112
|
+
'removeFromWishlistLabel',
|
|
113
|
+
'viewSimilarLabel',
|
|
114
|
+
]
|
|
115
|
+
const schemaOwnedLabelKeys = new Set(['emptyLabel'])
|
|
116
|
+
const schemas: Array<{ name: string; schema: z.AnyZodObject }> = [
|
|
117
|
+
{ name: 'productCardPropsSchema', schema: productCardPropsSchema },
|
|
118
|
+
{ name: 'productGridPropsSchema', schema: productGridPropsSchema },
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
for (const { name, schema } of schemas) {
|
|
122
|
+
const declaredKeys = Object.keys(schema.shape)
|
|
123
|
+
expect(declaredKeys.length, name).toBeGreaterThan(0)
|
|
124
|
+
for (const key of declaredKeys) {
|
|
125
|
+
expect(runtimeOnlyKeys, `${name}.${key}`).not.toContain(key)
|
|
126
|
+
expect(key, `${name}.${key}`).not.toMatch(/^on[A-Z]/)
|
|
127
|
+
if (!schemaOwnedLabelKeys.has(key)) {
|
|
128
|
+
expect(key, `${name}.${key}`).not.toMatch(/Label$/)
|
|
129
|
+
}
|
|
130
|
+
expect(schema.shape[key], `${name}.${key}`).not.toBeInstanceOf(z.ZodFunction)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('rejects non-positive maxItems and skeletonCount', () => {
|
|
136
|
+
expect(productGridPropsSchema.safeParse({ items: [], maxItems: 0 }).success).toBe(false)
|
|
137
|
+
expect(productGridPropsSchema.safeParse({ items: [], skeletonCount: 0 }).success).toBe(false)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
describe('category cell and listing contracts', () => {
|
|
142
|
+
const category = { id: 'cat-tools', name: 'Herramientas' }
|
|
143
|
+
|
|
144
|
+
it('keeps category cell and listing props JSON-serializable and callback-free', () => {
|
|
145
|
+
const samples: Array<{ name: string; schema: z.AnyZodObject; props: unknown }> = [
|
|
146
|
+
{
|
|
147
|
+
name: 'categoryCardPropsSchema',
|
|
148
|
+
schema: categoryCardPropsSchema,
|
|
149
|
+
props: { category, presentation: 'grid', browseLabel: 'Explorar' },
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'categoryGridPropsSchema',
|
|
153
|
+
schema: categoryGridPropsSchema,
|
|
154
|
+
props: { categories: [category], presentation: 'grid', title: 'Categorías', maxItems: 4 },
|
|
155
|
+
},
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
for (const { name, schema, props } of samples) {
|
|
159
|
+
const parsed = schema.parse(props)
|
|
160
|
+
expect(JSON.parse(JSON.stringify(parsed)), name).toEqual(parsed)
|
|
161
|
+
for (const key of Object.keys(schema.shape)) {
|
|
162
|
+
expect(key, `${name}.${key}`).not.toMatch(/^on[A-Z]/)
|
|
163
|
+
expect(schema.shape[key], `${name}.${key}`).not.toBeInstanceOf(z.ZodFunction)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('keeps display labels serializable strings and rejects a collection in the cell contract', () => {
|
|
169
|
+
expect(categoryCardPropsSchema.safeParse({ category, browseLabel: () => 'Explorar' }).success).toBe(false)
|
|
170
|
+
expect(categoryGridPropsSchema.safeParse({ categories: [], emptyLabel: () => 'Vacío' }).success).toBe(false)
|
|
171
|
+
expect(categoryCardPropsSchema.safeParse({ categories: [category] }).success).toBe(false)
|
|
172
|
+
})
|
|
173
|
+
})
|