@thorprovider/blocks 0.1.1 → 0.1.3
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/.turbo/turbo-build.log +15 -15
- package/.turbo/turbo-test.log +42 -5
- package/AGENTS.md +1 -1
- package/README.md +94 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts.d.mts +1266 -97
- package/dist/contracts.d.ts +1266 -97
- package/dist/contracts.js +225 -9
- package/dist/contracts.js.map +1 -1
- package/dist/contracts.mjs +207 -10
- package/dist/contracts.mjs.map +1 -1
- package/dist/index.d.mts +756 -96
- package/dist/index.d.ts +756 -96
- package/dist/index.js +5114 -3702
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4939 -3551
- package/dist/index.mjs.map +1 -1
- package/docs/standards/theming.md +32 -5
- package/package.json +2 -2
- package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +136 -93
- package/src/blocks/e-commerce/category-filters/category-filter-2.test.tsx +513 -0
- package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +728 -148
- package/src/blocks/e-commerce/checkout-forms/checkout-confirmation-fulfilment-progress.tsx +14 -8
- package/src/blocks/e-commerce/checkout-forms/checkout-confirmation.test.tsx +136 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-confirmation.tsx +145 -99
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +215 -102
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +6 -2
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-shipping-step.tsx +51 -2
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +216 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +114 -11
- 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/mobile-category-drawer.test.tsx +42 -2
- package/src/blocks/e-commerce/navigation/mobile-category-drawer.tsx +10 -8
- 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/product-category-2.test.tsx +51 -0
- package/src/blocks/e-commerce/product-categories/product-category-2.tsx +56 -36
- package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +88 -0
- package/src/blocks/e-commerce/product-list/product-card-1.tsx +141 -80
- 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-1.test.tsx +182 -0
- package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +298 -129
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +229 -0
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.tsx +313 -110
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +72 -0
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +20 -1
- package/src/blocks/marketing/footers/footer-section-1.test.tsx +117 -0
- package/src/blocks/marketing/footers/footer-section-1.tsx +46 -9
- package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +38 -0
- package/src/blocks/marketing/navbars/navbar-4-account-menu.tsx +30 -14
- package/src/blocks/marketing/navbars/navbar-4-cart-sheet.test.tsx +204 -0
- package/src/blocks/marketing/navbars/navbar-4-cart-sheet.tsx +144 -21
- package/src/blocks/marketing/navbars/navbar-4.test.tsx +233 -0
- package/src/blocks/marketing/navbars/navbar-4.tsx +235 -60
- package/src/index.ts +56 -0
- package/src/lib/cart.test.ts +15 -0
- package/src/lib/cart.ts +11 -0
- package/src/lib/contracts-curated.test.ts +207 -0
- package/src/lib/contracts-server-boundary.test.ts +52 -0
- package/src/lib/contracts.ts +234 -6
- package/src/lib/money.test.ts +64 -0
- package/src/lib/money.ts +65 -0
- package/tsup.config.ts +0 -1
- package/vitest.config.ts +9 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { renderToStaticMarkup } from 'react-dom/server'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import { ShoppingCart4, type ShoppingCart4Item, type ShoppingCart4Totals } from './shopping-cart-4'
|
|
4
|
+
|
|
5
|
+
const items: ShoppingCart4Item[] = [
|
|
6
|
+
{
|
|
7
|
+
id: 'line_1',
|
|
8
|
+
name: 'Taladro',
|
|
9
|
+
price: 45,
|
|
10
|
+
quantity: 2,
|
|
11
|
+
image: 'https://cdn.example/taladro.jpg',
|
|
12
|
+
lineTotal: { amount: '90.00', currencyCode: 'USD' },
|
|
13
|
+
},
|
|
14
|
+
{ id: 'line_2', name: 'Batería', price: 20, quantity: 1 },
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
const totals: ShoppingCart4Totals = {
|
|
18
|
+
subtotal: { amount: '110.00', currencyCode: 'USD' },
|
|
19
|
+
discount: { amount: '10.00', currencyCode: 'USD' },
|
|
20
|
+
tax: { amount: '8.00', currencyCode: 'USD' },
|
|
21
|
+
shipping: { amount: '0', currencyCode: 'USD' },
|
|
22
|
+
total: { amount: '108.00', currencyCode: 'USD' },
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const formatMoney = (money: { amount: string; currencyCode: string }) =>
|
|
26
|
+
`${money.currencyCode} ${money.amount}`
|
|
27
|
+
|
|
28
|
+
describe('ShoppingCart4 — backend-authoritative totals', () => {
|
|
29
|
+
it('renders supplied backend totals verbatim (no local arithmetic)', () => {
|
|
30
|
+
const html = renderToStaticMarkup(
|
|
31
|
+
<ShoppingCart4 items={items} promotions={[]} totals={totals} formatMoney={formatMoney} />,
|
|
32
|
+
)
|
|
33
|
+
expect(html).toContain('USD 110.00')
|
|
34
|
+
expect(html).toContain('USD 10.00')
|
|
35
|
+
expect(html).toContain('USD 8.00')
|
|
36
|
+
expect(html).toContain('Gratis')
|
|
37
|
+
expect(html).toContain('USD 108.00')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('does not invent subtotal or total when none are supplied', () => {
|
|
41
|
+
const html = renderToStaticMarkup(
|
|
42
|
+
<ShoppingCart4 items={items} promotions={[]} formatMoney={formatMoney} />,
|
|
43
|
+
)
|
|
44
|
+
expect(html).not.toContain('Subtotal')
|
|
45
|
+
expect(html).not.toContain('Total')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('renders a controlled pending state', () => {
|
|
49
|
+
const html = renderToStaticMarkup(
|
|
50
|
+
<ShoppingCart4 items={items} promotions={[]} totalsState='pending' />,
|
|
51
|
+
)
|
|
52
|
+
expect(html).toContain('Actualizando totales')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('renders a controlled error state with a recovery action', () => {
|
|
56
|
+
const html = renderToStaticMarkup(
|
|
57
|
+
<ShoppingCart4
|
|
58
|
+
items={items}
|
|
59
|
+
promotions={[]}
|
|
60
|
+
totalsState='error'
|
|
61
|
+
onRetryTotals={() => {}}
|
|
62
|
+
/>,
|
|
63
|
+
)
|
|
64
|
+
expect(html).toContain('No se pudieron actualizar los totales')
|
|
65
|
+
expect(html).toContain('Reintentar')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('omits an absent line image without emitting an empty src', () => {
|
|
69
|
+
const html = renderToStaticMarkup(
|
|
70
|
+
<ShoppingCart4 items={items} promotions={[]} totals={totals} formatMoney={formatMoney} />,
|
|
71
|
+
)
|
|
72
|
+
expect(html).not.toMatch(/src=""/)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('does not fabricate a delivery estimate or express payment controls', () => {
|
|
76
|
+
const html = renderToStaticMarkup(
|
|
77
|
+
<ShoppingCart4 items={items} promotions={[]} totals={totals} formatMoney={formatMoney} />,
|
|
78
|
+
)
|
|
79
|
+
expect(html).not.toContain('Entrega estimada')
|
|
80
|
+
expect(html).not.toContain('Apple Pay')
|
|
81
|
+
expect(html).not.toContain('Google Pay')
|
|
82
|
+
expect(html).not.toContain('Compra rápida')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('never renders a fake zero for absent or malformed required totals', () => {
|
|
86
|
+
const html = renderToStaticMarkup(
|
|
87
|
+
<ShoppingCart4
|
|
88
|
+
items={items}
|
|
89
|
+
promotions={[]}
|
|
90
|
+
totals={{
|
|
91
|
+
subtotal: { amount: '', currencyCode: 'USD' },
|
|
92
|
+
total: { amount: 'abc', currencyCode: 'USD' },
|
|
93
|
+
}}
|
|
94
|
+
formatMoney={formatMoney}
|
|
95
|
+
/>,
|
|
96
|
+
)
|
|
97
|
+
expect(html).not.toContain('USD 0')
|
|
98
|
+
expect(html).toContain('Totales no disponibles')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('preserves a legitimate zero total', () => {
|
|
102
|
+
const html = renderToStaticMarkup(
|
|
103
|
+
<ShoppingCart4
|
|
104
|
+
items={items}
|
|
105
|
+
promotions={[]}
|
|
106
|
+
totals={{
|
|
107
|
+
subtotal: { amount: '0', currencyCode: 'USD' },
|
|
108
|
+
total: { amount: '0', currencyCode: 'USD' },
|
|
109
|
+
}}
|
|
110
|
+
formatMoney={formatMoney}
|
|
111
|
+
/>,
|
|
112
|
+
)
|
|
113
|
+
expect(html).toContain('USD 0')
|
|
114
|
+
expect(html).not.toContain('Totales no disponibles')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('shows an unavailable marker (not zero) for a supplied but malformed line total', () => {
|
|
118
|
+
const html = renderToStaticMarkup(
|
|
119
|
+
<ShoppingCart4
|
|
120
|
+
items={[{ id: 'line_x', name: 'Pieza', price: 10, quantity: 1, lineTotal: { amount: '', currencyCode: 'USD' } }]}
|
|
121
|
+
promotions={[]}
|
|
122
|
+
totals={totals}
|
|
123
|
+
formatMoney={formatMoney}
|
|
124
|
+
/>,
|
|
125
|
+
)
|
|
126
|
+
expect(html).toContain('—')
|
|
127
|
+
expect(html).not.toContain('USD 0')
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('renders absolute quantities from props (cart contract, not a delta)', () => {
|
|
131
|
+
const html = renderToStaticMarkup(
|
|
132
|
+
<ShoppingCart4 items={items} promotions={[]} totals={totals} formatMoney={formatMoney} />,
|
|
133
|
+
)
|
|
134
|
+
expect(html).toContain('>2<')
|
|
135
|
+
expect(html).toContain('>1<')
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
describe('ShoppingCart4 — presentation and action availability', () => {
|
|
140
|
+
it('defaults to the compact collapsible card', () => {
|
|
141
|
+
const html = renderToStaticMarkup(
|
|
142
|
+
<ShoppingCart4 items={items} promotions={[]} totals={totals} formatMoney={formatMoney} />,
|
|
143
|
+
)
|
|
144
|
+
expect(html).toContain('max-w-md')
|
|
145
|
+
expect(html).toContain('Contraer carrito')
|
|
146
|
+
expect(html).toContain('max-h-64')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('renders page presentation as a wide, always-expanded review with a heading', () => {
|
|
150
|
+
const html = renderToStaticMarkup(
|
|
151
|
+
<ShoppingCart4
|
|
152
|
+
items={items}
|
|
153
|
+
promotions={[]}
|
|
154
|
+
totals={totals}
|
|
155
|
+
formatMoney={formatMoney}
|
|
156
|
+
presentation='page'
|
|
157
|
+
/>,
|
|
158
|
+
)
|
|
159
|
+
expect(html).toContain('max-w-3xl')
|
|
160
|
+
expect(html).toContain('<h1')
|
|
161
|
+
expect(html).not.toContain('Contraer carrito')
|
|
162
|
+
expect(html).not.toContain('max-h-64')
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('offers a continue-shopping action in page presentation', () => {
|
|
166
|
+
const html = renderToStaticMarkup(
|
|
167
|
+
<ShoppingCart4
|
|
168
|
+
items={items}
|
|
169
|
+
promotions={[]}
|
|
170
|
+
totals={totals}
|
|
171
|
+
formatMoney={formatMoney}
|
|
172
|
+
presentation='page'
|
|
173
|
+
onContinueShopping={() => {}}
|
|
174
|
+
/>,
|
|
175
|
+
)
|
|
176
|
+
expect(html).toContain('Seguir comprando')
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('suppresses checkout when the checkout feature is unavailable', () => {
|
|
180
|
+
const html = renderToStaticMarkup(
|
|
181
|
+
<ShoppingCart4
|
|
182
|
+
items={items}
|
|
183
|
+
promotions={[]}
|
|
184
|
+
totals={totals}
|
|
185
|
+
formatMoney={formatMoney}
|
|
186
|
+
presentation='page'
|
|
187
|
+
checkoutUnavailable
|
|
188
|
+
/>,
|
|
189
|
+
)
|
|
190
|
+
expect(html).not.toContain('Ver carrito y finalizar')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('disables checkout while the cart is not ready', () => {
|
|
194
|
+
const html = renderToStaticMarkup(
|
|
195
|
+
<ShoppingCart4
|
|
196
|
+
items={items}
|
|
197
|
+
promotions={[]}
|
|
198
|
+
totals={totals}
|
|
199
|
+
formatMoney={formatMoney}
|
|
200
|
+
presentation='page'
|
|
201
|
+
checkoutDisabled
|
|
202
|
+
/>,
|
|
203
|
+
)
|
|
204
|
+
expect(html).toMatch(/<button[^>]*disabled[^>]*>[^<]*Ver carrito y finalizar/)
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
describe('ShoppingCart4 — accessibility', () => {
|
|
209
|
+
it('names every line mutation control', () => {
|
|
210
|
+
const html = renderToStaticMarkup(
|
|
211
|
+
<ShoppingCart4 items={items} promotions={[]} totals={totals} formatMoney={formatMoney} />,
|
|
212
|
+
)
|
|
213
|
+
expect(html).toContain('aria-label="Disminuir cantidad, Taladro"')
|
|
214
|
+
expect(html).toContain('aria-label="Aumentar cantidad, Taladro"')
|
|
215
|
+
expect(html).toContain('aria-label="Quitar Taladro"')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('announces pending totals politely and errors as an alert', () => {
|
|
219
|
+
const pending = renderToStaticMarkup(
|
|
220
|
+
<ShoppingCart4 items={items} promotions={[]} totalsState='pending' />,
|
|
221
|
+
)
|
|
222
|
+
expect(pending).toContain('aria-live="polite"')
|
|
223
|
+
expect(pending).toContain('Actualizando totales')
|
|
224
|
+
const error = renderToStaticMarkup(
|
|
225
|
+
<ShoppingCart4 items={items} promotions={[]} totalsState='error' />,
|
|
226
|
+
)
|
|
227
|
+
expect(error).toMatch(/role="alert"/)
|
|
228
|
+
})
|
|
229
|
+
})
|