@thorprovider/blocks 0.1.3 → 2.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.
Files changed (178) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/README.md +228 -68
  3. package/docs/standards/data-contracts.md +13 -2
  4. package/package.json +26 -10
  5. package/scripts/fix-esm-extensions.mjs +40 -0
  6. package/src/blocks/application/login-forms/login-page.test.tsx +190 -0
  7. package/src/blocks/application/login-forms/login-page.tsx +240 -0
  8. package/src/blocks/application/password-recovery/forgot-password-page-1.tsx +6 -8
  9. package/src/blocks/application/signup-forms/signup-page-1.tsx +127 -129
  10. package/src/blocks/application/verification/verify-1.tsx +2 -2
  11. package/src/blocks/application/viewport-ownership.test.tsx +41 -0
  12. package/src/blocks/e-commerce/category-filters/category-listing-filter-fields.tsx +218 -0
  13. package/src/blocks/e-commerce/category-filters/{category-filter-2.test.tsx → category-listing.test.tsx} +287 -199
  14. package/src/blocks/e-commerce/category-filters/category-listing.tsx +934 -0
  15. package/src/blocks/e-commerce/checkout-forms/checkout-contact-step.tsx +149 -0
  16. package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-country-field.tsx → checkout-country-field.tsx} +10 -8
  17. package/src/blocks/e-commerce/checkout-forms/checkout-order-summary.tsx +230 -0
  18. package/src/blocks/e-commerce/checkout-forms/checkout-payment-step.tsx +100 -0
  19. package/src/blocks/e-commerce/checkout-forms/checkout-progress.tsx +62 -0
  20. package/src/blocks/e-commerce/checkout-forms/checkout-review-step.tsx +59 -0
  21. package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-shipping-step.tsx → checkout-shipping-step.tsx} +65 -41
  22. package/src/blocks/e-commerce/checkout-forms/checkout.test.tsx +478 -0
  23. package/src/blocks/e-commerce/checkout-forms/checkout.tsx +550 -0
  24. package/src/blocks/e-commerce/navigation/storefront-navbar-account-menu.test.tsx +56 -0
  25. package/src/blocks/{marketing/navbars/navbar-4-account-menu.tsx → e-commerce/navigation/storefront-navbar-account-menu.tsx} +3 -3
  26. package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.test.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.test.tsx} +22 -22
  27. package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.tsx} +3 -3
  28. package/src/blocks/{marketing/navbars/navbar-4-mobile-nav.tsx → e-commerce/navigation/storefront-navbar-mobile-nav.tsx} +4 -12
  29. package/src/blocks/{marketing/navbars/navbar-4-search-bar.tsx → e-commerce/navigation/storefront-navbar-search-bar.tsx} +3 -3
  30. package/src/blocks/{marketing/navbars/navbar-4.test.tsx → e-commerce/navigation/storefront-navbar.test.tsx} +67 -36
  31. package/src/blocks/{marketing/navbars/navbar-4.tsx → e-commerce/navigation/storefront-navbar.tsx} +43 -25
  32. package/src/blocks/e-commerce/product-categories/category-card-grid.test.tsx +122 -0
  33. package/src/blocks/e-commerce/product-categories/category-card.test.tsx +68 -0
  34. package/src/blocks/e-commerce/product-categories/category-card.tsx +172 -0
  35. package/src/blocks/e-commerce/product-categories/category-grid.test.tsx +67 -0
  36. package/src/blocks/e-commerce/product-categories/category-shared.tsx +109 -0
  37. package/src/blocks/e-commerce/product-categories/product-category-grid.tsx +170 -0
  38. package/src/blocks/e-commerce/product-categories/product-category.test.tsx +266 -0
  39. package/src/blocks/e-commerce/product-categories/product-category.tsx +462 -0
  40. package/src/blocks/e-commerce/product-list/product-card.test.tsx +263 -0
  41. package/src/blocks/e-commerce/product-list/product-card.tsx +447 -0
  42. package/src/blocks/e-commerce/product-list/product-grid.test.tsx +162 -0
  43. package/src/blocks/e-commerce/product-list/product-grid.tsx +114 -0
  44. package/src/blocks/e-commerce/product-overview/product-overview-gallery.tsx +71 -0
  45. package/src/blocks/e-commerce/product-overview/{product-overview-5-lightbox-tab.tsx → product-overview-lightbox-tab.tsx} +35 -23
  46. package/src/blocks/e-commerce/product-overview/{product-overview-5-reviews-tab.tsx → product-overview-reviews-tab.tsx} +40 -17
  47. package/src/blocks/e-commerce/product-overview/{product-overview-5-tabs.tsx → product-overview-tabs.tsx} +8 -7
  48. package/src/blocks/e-commerce/product-overview/product-overview.test.tsx +283 -0
  49. package/src/blocks/e-commerce/product-overview/product-overview.tsx +1186 -0
  50. package/src/blocks/e-commerce/reviews/review-rating-2.tsx +5 -6
  51. package/src/blocks/e-commerce/shopping-carts/shopping-cart.test.tsx +399 -0
  52. package/src/blocks/e-commerce/shopping-carts/{shopping-cart-4.tsx → shopping-cart.tsx} +119 -85
  53. package/src/blocks/e-commerce/storefront-hero/storefront-hero.test.tsx +412 -0
  54. package/src/blocks/e-commerce/storefront-hero/storefront-hero.tsx +1283 -0
  55. package/src/blocks/marketing/features/feature.test.tsx +153 -0
  56. package/src/blocks/marketing/features/feature.tsx +195 -0
  57. package/src/blocks/marketing/footers/footer-section-accessibility.test.tsx +118 -0
  58. package/src/blocks/marketing/footers/footer-section-actions.test.tsx +131 -0
  59. package/src/blocks/marketing/footers/footer-section-data.test.tsx +127 -0
  60. package/src/blocks/marketing/footers/footer-section-native-links.test.tsx +100 -0
  61. package/src/blocks/marketing/footers/footer-section-public-api.test.tsx +11 -0
  62. package/src/blocks/marketing/footers/footer-section.test.tsx +46 -0
  63. package/src/blocks/marketing/footers/footer-section.tsx +532 -0
  64. package/src/blocks/marketing/navbars/navbar-public-api.test.tsx +57 -0
  65. package/src/blocks/marketing/navbars/navbar.mega.test.tsx +149 -0
  66. package/src/blocks/marketing/navbars/navbar.test.tsx +155 -0
  67. package/src/blocks/marketing/navbars/navbar.tsx +735 -0
  68. package/src/blocks/marketing/testimonials/testimonial-section.test.tsx +171 -0
  69. package/src/blocks/marketing/testimonials/testimonial-section.tsx +237 -0
  70. package/src/index.ts +156 -128
  71. package/src/lib/contracts-curated.test.ts +47 -29
  72. package/src/lib/contracts.test.ts +198 -2
  73. package/src/lib/contracts.ts +410 -16
  74. package/src/ui/button-group.tsx +1 -1
  75. package/src/ui/carousel.tsx +1 -1
  76. package/src/ui/dialog.tsx +1 -1
  77. package/src/ui/field.tsx +2 -2
  78. package/src/ui/input-group.tsx +3 -3
  79. package/src/ui/pagination.tsx +1 -1
  80. package/src/ui/sidebar.tsx +7 -7
  81. package/src/ui/toggle-group.tsx +1 -1
  82. package/tsconfig.build.json +12 -0
  83. package/tsup.config.ts +11 -7
  84. package/.turbo/turbo-build.log +0 -24
  85. package/.turbo/turbo-test.log +0 -47
  86. package/.turbo/turbo-type-check.log +0 -0
  87. package/dist/.tsbuildinfo +0 -1
  88. package/dist/contracts.d.mts +0 -1732
  89. package/dist/contracts.d.ts +0 -1732
  90. package/dist/contracts.js +0 -423
  91. package/dist/contracts.js.map +0 -1
  92. package/dist/contracts.mjs +0 -365
  93. package/dist/contracts.mjs.map +0 -1
  94. package/dist/index.d.mts +0 -3068
  95. package/dist/index.d.ts +0 -3068
  96. package/dist/index.js +0 -17834
  97. package/dist/index.js.map +0 -1
  98. package/dist/index.mjs +0 -17740
  99. package/dist/index.mjs.map +0 -1
  100. package/src/blocks/application/login-forms/login-page-1.tsx +0 -246
  101. package/src/blocks/application/login-forms/login-page-2.tsx +0 -207
  102. package/src/blocks/e-commerce/category-filters/category-filter-1.tsx +0 -260
  103. package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +0 -222
  104. package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +0 -921
  105. package/src/blocks/e-commerce/category-filters/category-filter-4-chip-rail.tsx +0 -57
  106. package/src/blocks/e-commerce/category-filters/category-filter-4-drawer.tsx +0 -124
  107. package/src/blocks/e-commerce/category-filters/category-filter-4-fields.tsx +0 -170
  108. package/src/blocks/e-commerce/category-filters/category-filter-4-sidebar.tsx +0 -52
  109. package/src/blocks/e-commerce/category-filters/category-filter-4-sort-sheet.tsx +0 -57
  110. package/src/blocks/e-commerce/category-filters/category-filter-4-state.ts +0 -68
  111. package/src/blocks/e-commerce/category-filters/category-filter-4.tsx +0 -298
  112. package/src/blocks/e-commerce/checkout-forms/card-formatting.test.ts +0 -47
  113. package/src/blocks/e-commerce/checkout-forms/card-formatting.ts +0 -9
  114. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-contact-step.tsx +0 -96
  115. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +0 -252
  116. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +0 -188
  117. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-progress.tsx +0 -36
  118. package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +0 -216
  119. package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +0 -338
  120. package/src/blocks/e-commerce/checkout-forms/checkout-form-2-order-summary.tsx +0 -130
  121. package/src/blocks/e-commerce/checkout-forms/checkout-form-2-payment-card.tsx +0 -175
  122. package/src/blocks/e-commerce/checkout-forms/checkout-form-2-shipping-card.tsx +0 -190
  123. package/src/blocks/e-commerce/checkout-forms/checkout-form-2.tsx +0 -312
  124. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-information-step.tsx +0 -91
  125. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-order-summary.tsx +0 -110
  126. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-payment-step.tsx +0 -137
  127. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-progress.tsx +0 -68
  128. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-review-step.tsx +0 -79
  129. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-shipping-step.tsx +0 -172
  130. package/src/blocks/e-commerce/checkout-forms/checkout-form-3.tsx +0 -392
  131. package/src/blocks/e-commerce/product-categories/avatar-group.tsx +0 -86
  132. package/src/blocks/e-commerce/product-categories/product-category-1.tsx +0 -126
  133. package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +0 -51
  134. package/src/blocks/e-commerce/product-categories/product-category-2.tsx +0 -120
  135. package/src/blocks/e-commerce/product-categories/product-category-4.tsx +0 -129
  136. package/src/blocks/e-commerce/product-categories/product-category-5.tsx +0 -218
  137. package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +0 -88
  138. package/src/blocks/e-commerce/product-list/product-card-1.tsx +0 -192
  139. package/src/blocks/e-commerce/product-list/product-card-2.tsx +0 -71
  140. package/src/blocks/e-commerce/product-list/product-card-3-reaction-toggle.tsx +0 -166
  141. package/src/blocks/e-commerce/product-list/product-card-3.tsx +0 -215
  142. package/src/blocks/e-commerce/product-list/product-card-5-checkbox-check.tsx +0 -98
  143. package/src/blocks/e-commerce/product-list/product-card-5-reaction-toggle.tsx +0 -171
  144. package/src/blocks/e-commerce/product-list/product-card-5.tsx +0 -367
  145. package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +0 -182
  146. package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +0 -370
  147. package/src/blocks/e-commerce/product-overview/product-overview-2.tsx +0 -272
  148. package/src/blocks/e-commerce/product-overview/product-overview-5-gallery.tsx +0 -59
  149. package/src/blocks/e-commerce/product-overview/product-overview-5.tsx +0 -274
  150. package/src/blocks/e-commerce/shopping-carts/shopping-cart-1-spinning-counter.tsx +0 -142
  151. package/src/blocks/e-commerce/shopping-carts/shopping-cart-1.tsx +0 -291
  152. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-item-row.tsx +0 -110
  153. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-recommendations.tsx +0 -51
  154. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-spinning-counter.tsx +0 -146
  155. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2.tsx +0 -295
  156. package/src/blocks/e-commerce/shopping-carts/shopping-cart-3-spinning-counter.tsx +0 -142
  157. package/src/blocks/e-commerce/shopping-carts/shopping-cart-3.tsx +0 -342
  158. package/src/blocks/e-commerce/shopping-carts/shopping-cart-4-spinning-counter.tsx +0 -146
  159. package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +0 -229
  160. package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +0 -72
  161. package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +0 -263
  162. package/src/blocks/e-commerce/storefront-hero/storefront-hero-2.tsx +0 -283
  163. package/src/blocks/e-commerce/storefront-hero/storefront-hero-5.tsx +0 -318
  164. package/src/blocks/e-commerce/storefront-hero/storefront-hero-6.tsx +0 -205
  165. package/src/blocks/marketing/features/feature-1.tsx +0 -97
  166. package/src/blocks/marketing/features/feature-2.tsx +0 -82
  167. package/src/blocks/marketing/footers/footer-section-1.test.tsx +0 -117
  168. package/src/blocks/marketing/footers/footer-section-1.tsx +0 -178
  169. package/src/blocks/marketing/footers/footer-section-3.tsx +0 -192
  170. package/src/blocks/marketing/footers/footer-section-4.tsx +0 -355
  171. package/src/blocks/marketing/navbars/navbar-1.tsx +0 -267
  172. package/src/blocks/marketing/navbars/navbar-2.tsx +0 -351
  173. package/src/blocks/marketing/navbars/navbar-3.tsx +0 -303
  174. package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +0 -38
  175. package/src/blocks/marketing/navbars/navbar-4-like-button.tsx +0 -177
  176. package/src/blocks/marketing/navbars/navbar-4-product-grid.tsx +0 -219
  177. package/src/blocks/marketing/testimonials/testimonial-1.tsx +0 -141
  178. package/src/blocks/marketing/testimonials/testimonial-2.tsx +0 -108
@@ -0,0 +1,127 @@
1
+ // @vitest-environment jsdom
2
+ import { fireEvent, render, screen } from '@testing-library/react'
3
+ import { AtSign } from 'lucide-react'
4
+ import { describe, expect, it, vi } from 'vitest'
5
+
6
+ import {
7
+ FooterSection,
8
+ type FooterSectionProps,
9
+ type FooterSocialLink,
10
+ } from './footer-section'
11
+
12
+ const baseProps = {
13
+ presentation: 'contact',
14
+ brandName: 'Thor Provider',
15
+ linkColumns: [],
16
+ } satisfies FooterSectionProps
17
+
18
+ const instagram = {
19
+ label: 'Instagram',
20
+ href: '/redes/instagram',
21
+ icon: 'instagram',
22
+ } satisfies FooterSocialLink
23
+
24
+ describe('FooterSection serializable social content and list identities', () => {
25
+ it('round-trips social identifiers as plain JSON data', () => {
26
+ const serialized = JSON.stringify([instagram])
27
+
28
+ expect(serialized).toBe(
29
+ '[{"label":"Instagram","href":"/redes/instagram","icon":"instagram"}]',
30
+ )
31
+ expect(JSON.parse(serialized)).toEqual([instagram])
32
+ })
33
+
34
+ it('renders a host-bound icon for its serializable identifier', () => {
35
+ render(
36
+ <FooterSection
37
+ {...baseProps}
38
+ socialLinks={[instagram]}
39
+ socialIcons={{ instagram: AtSign }}
40
+ onSocialClick={() => undefined}
41
+ />,
42
+ )
43
+
44
+ const socialLink = screen.getByRole('link', { name: 'Instagram' })
45
+ expect(socialLink.getAttribute('href')).toBe('/redes/instagram')
46
+ expect(socialLink.querySelector('svg')).not.toBeNull()
47
+ })
48
+
49
+ it('uses an optional accessible name without changing the raw social label', () => {
50
+ const onSocialClick = vi.fn()
51
+ const socialLink = { ...instagram, ariaLabel: 'Seguir en Instagram' }
52
+
53
+ render(
54
+ <FooterSection
55
+ {...baseProps}
56
+ socialLinks={[socialLink]}
57
+ socialIcons={{ instagram: AtSign }}
58
+ onSocialClick={onSocialClick}
59
+ />,
60
+ )
61
+
62
+ const control = screen.getByRole('link', { name: 'Seguir en Instagram' })
63
+ expect(control.textContent).toContain('Instagram')
64
+ fireEvent.click(control)
65
+ expect(onSocialClick).toHaveBeenCalledWith('Instagram')
66
+ })
67
+
68
+ it('keeps the provider label visible when its icon identifier is unmapped', () => {
69
+ render(
70
+ <FooterSection
71
+ {...baseProps}
72
+ socialLinks={[instagram]}
73
+ socialIcons={{}}
74
+ onSocialClick={() => undefined}
75
+ />,
76
+ )
77
+
78
+ const socialLink = screen.getByRole('link', { name: 'Instagram' })
79
+ expect(socialLink.textContent).toContain('Instagram')
80
+ expect(socialLink.querySelector('svg')).toBeNull()
81
+ })
82
+
83
+ it('rejects duplicate column identities instead of emitting duplicate keys', () => {
84
+ expect(() =>
85
+ render(
86
+ <FooterSection
87
+ {...baseProps}
88
+ linkColumns={[
89
+ { title: 'Servicios', links: [{ label: 'Talleres' }] },
90
+ { title: 'Servicios', links: [{ label: 'Repuestos' }] },
91
+ ]}
92
+ />,
93
+ ),
94
+ ).toThrow(/column.*keys must be unique/i)
95
+ })
96
+
97
+ it('rejects duplicate link identities within a column', () => {
98
+ expect(() =>
99
+ render(
100
+ <FooterSection
101
+ {...baseProps}
102
+ linkColumns={[
103
+ {
104
+ title: 'Servicios',
105
+ links: [
106
+ { label: 'Talleres', href: '/talleres' },
107
+ { label: 'Talleres', href: '/talleres' },
108
+ ],
109
+ },
110
+ ]}
111
+ />,
112
+ ),
113
+ ).toThrow(/link.*keys must be unique/i)
114
+ })
115
+
116
+ it('rejects duplicate social identities instead of emitting duplicate keys', () => {
117
+ expect(() =>
118
+ render(
119
+ <FooterSection
120
+ {...baseProps}
121
+ socialLinks={[instagram, instagram]}
122
+ onSocialClick={() => undefined}
123
+ />,
124
+ ),
125
+ ).toThrow(/social.*keys must be unique/i)
126
+ })
127
+ })
@@ -0,0 +1,100 @@
1
+ // @vitest-environment jsdom
2
+ import { render, screen } from '@testing-library/react'
3
+ import { AtSign } from 'lucide-react'
4
+ import { describe, expect, it, vi } from 'vitest'
5
+
6
+ import { FooterSection, type FooterSectionProps } from './footer-section'
7
+
8
+ const nativeProps = {
9
+ presentation: 'brand-columns',
10
+ linkBehavior: 'native',
11
+ brandName: 'Thor Provider',
12
+ linkColumns: [
13
+ {
14
+ title: 'Repuestos',
15
+ links: [{ label: 'Catálogo de repuestos', href: '/repuestos' }],
16
+ },
17
+ ],
18
+ socialLinks: [
19
+ { label: 'Instagram', href: '/redes/instagram', icon: 'instagram' },
20
+ ],
21
+ socialIcons: { instagram: AtSign },
22
+ }
23
+
24
+ describe('FooterSection native link compatibility', () => {
25
+ it('keeps native column hrefs separate from host-controlled social links', () => {
26
+ render(
27
+ <FooterSection
28
+ {...(nativeProps as unknown as FooterSectionProps)}
29
+ />,
30
+ )
31
+
32
+ expect(
33
+ screen
34
+ .getByRole('link', { name: 'Catálogo de repuestos' })
35
+ .getAttribute('href'),
36
+ ).toBe('/repuestos')
37
+ expect(screen.getByText('Instagram').closest('a')).toBeNull()
38
+ })
39
+
40
+ it('notifies native column callbacks without preventing browser navigation', () => {
41
+ const onLinkClick = vi.fn()
42
+ const props = {
43
+ ...nativeProps,
44
+ onLinkClick,
45
+ } as unknown as FooterSectionProps
46
+
47
+ render(<FooterSection {...props} />)
48
+
49
+ const columnLink = screen.getByRole('link', {
50
+ name: 'Catálogo de repuestos',
51
+ })
52
+ const columnEvent = new MouseEvent('click', {
53
+ bubbles: true,
54
+ cancelable: true,
55
+ })
56
+ columnLink.dispatchEvent(columnEvent)
57
+
58
+ expect(onLinkClick).toHaveBeenCalledWith(
59
+ nativeProps.linkColumns[0]?.links[0],
60
+ )
61
+ expect(columnEvent.defaultPrevented).toBe(false)
62
+ expect(screen.getByText('Instagram').closest('a')).toBeNull()
63
+ })
64
+
65
+ it('keeps native social hrefs separate from host-controlled column links', () => {
66
+ const props = {
67
+ ...nativeProps,
68
+ linkBehavior: 'host',
69
+ socialLinkBehavior: 'native',
70
+ } as unknown as FooterSectionProps
71
+
72
+ render(<FooterSection {...props} />)
73
+
74
+ expect(screen.getByText('Catálogo de repuestos').closest('a')).toBeNull()
75
+ const socialLink = screen.getByRole('link', { name: 'Instagram' })
76
+ expect(socialLink.getAttribute('href')).toBe('/redes/instagram')
77
+ })
78
+
79
+ it('notifies native social callbacks without preventing browser navigation', () => {
80
+ const onSocialClick = vi.fn()
81
+ const props = {
82
+ ...nativeProps,
83
+ linkBehavior: 'host',
84
+ socialLinkBehavior: 'native',
85
+ onSocialClick,
86
+ } as unknown as FooterSectionProps
87
+
88
+ render(<FooterSection {...props} />)
89
+
90
+ const socialLink = screen.getByRole('link', { name: 'Instagram' })
91
+ const socialEvent = new MouseEvent('click', {
92
+ bubbles: true,
93
+ cancelable: true,
94
+ })
95
+ socialLink.dispatchEvent(socialEvent)
96
+
97
+ expect(onSocialClick).toHaveBeenCalledWith('Instagram')
98
+ expect(socialEvent.defaultPrevented).toBe(false)
99
+ })
100
+ })
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import * as blockExports from '../../../index'
3
+
4
+ describe('Blocks footer package exports', () => {
5
+ it('exposes the canonical footer and omits retired numbered adapters', () => {
6
+ expect(blockExports.FooterSection).toEqual(expect.any(Function))
7
+ expect('FooterSection1' in blockExports).toBe(false)
8
+ expect('FooterSection3' in blockExports).toBe(false)
9
+ expect('FooterSection4' in blockExports).toBe(false)
10
+ })
11
+ })
@@ -0,0 +1,46 @@
1
+ // @vitest-environment jsdom
2
+ import { render, screen } from '@testing-library/react'
3
+ import { describe, expect, it } from 'vitest'
4
+
5
+ import { FooterSection, type FooterSectionProps } from './footer-section'
6
+
7
+ const presentations = ['brand-columns', 'newsletter-grid', 'contact'] as const
8
+
9
+ const sharedProps = {
10
+ brandName: 'Thor Provider',
11
+ brandDescription: 'Repuestos y soluciones para talleres.',
12
+ linkColumns: [
13
+ {
14
+ title: 'Repuestos',
15
+ links: [{ label: 'Catálogo de repuestos', href: '/repuestos' }],
16
+ },
17
+ ],
18
+ copyright: '© 2026 Thor Provider',
19
+ } satisfies Omit<FooterSectionProps, 'presentation'>
20
+
21
+ describe('FooterSection', () => {
22
+ it('rejects a missing presentation instead of silently choosing a layout', () => {
23
+ expect(() =>
24
+ render(
25
+ <FooterSection
26
+ {...sharedProps}
27
+ presentation={undefined as unknown as FooterSectionProps['presentation']}
28
+ />,
29
+ ),
30
+ ).toThrow(/presentation/i)
31
+ })
32
+
33
+ it.each(presentations)(
34
+ 'renders the shared page-level footer responsibilities for %s',
35
+ (presentation) => {
36
+ render(<FooterSection {...sharedProps} presentation={presentation} />)
37
+
38
+ expect(screen.getByRole('contentinfo')).toBeTruthy()
39
+ expect(screen.getByText('Thor Provider')).toBeTruthy()
40
+ expect(screen.getByText('Repuestos y soluciones para talleres.')).toBeTruthy()
41
+ expect(screen.getByText('Repuestos')).toBeTruthy()
42
+ expect(screen.getByText('Catálogo de repuestos')).toBeTruthy()
43
+ expect(screen.getByText('© 2026 Thor Provider')).toBeTruthy()
44
+ },
45
+ )
46
+ })