@tallyui/components 1.0.0 → 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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +1076 -76
  3. package/dist/index.js +4662 -355
  4. package/package.json +27 -5
  5. package/src/cart/cart-line-actions.tsx +40 -0
  6. package/src/cart/cart-line.tsx +18 -32
  7. package/src/cart/cart-note-input.tsx +46 -0
  8. package/src/cart/cart-panel.tsx +39 -26
  9. package/src/cart/cart-total.tsx +43 -47
  10. package/src/cart/discount-badge.tsx +19 -0
  11. package/src/cart/index.ts +4 -1
  12. package/src/checkout/cash-tendered.tsx +101 -0
  13. package/src/checkout/change-display.tsx +19 -0
  14. package/src/checkout/index.ts +3 -0
  15. package/src/checkout/order-summary-line.tsx +7 -8
  16. package/src/checkout/order-summary.tsx +8 -7
  17. package/src/checkout/payment-method-card.tsx +10 -9
  18. package/src/checkout/payment-selector.tsx +5 -5
  19. package/src/checkout/receipt-preview.tsx +78 -0
  20. package/src/customer/customer-card.tsx +8 -9
  21. package/src/customer/customer-form.tsx +70 -0
  22. package/src/customer/customer-order-history.tsx +34 -0
  23. package/src/customer/customer-select.tsx +63 -24
  24. package/src/customer/index.ts +2 -0
  25. package/src/index.ts +112 -1
  26. package/src/input/filter-chip.tsx +85 -27
  27. package/src/input/index.ts +1 -0
  28. package/src/input/quantity-stepper.tsx +64 -0
  29. package/src/input/search-input.tsx +30 -7
  30. package/src/layout/checkout-layout.tsx +46 -0
  31. package/src/layout/index.ts +5 -0
  32. package/src/layout/live-tab-screen.tsx +54 -0
  33. package/src/layout/pos-layout.tsx +64 -0
  34. package/src/layout/settings-layout.tsx +58 -0
  35. package/src/layout/store-settings-choice-screen.tsx +142 -0
  36. package/src/order/index.ts +4 -0
  37. package/src/order/order-card.tsx +48 -0
  38. package/src/order/order-detail.tsx +82 -0
  39. package/src/order/order-list.tsx +39 -0
  40. package/src/order/order-status-badge.tsx +32 -0
  41. package/src/product/category-nav.tsx +70 -0
  42. package/src/product/index.ts +3 -0
  43. package/src/product/product-card.tsx +36 -8
  44. package/src/product/product-grid.tsx +25 -6
  45. package/src/product/product-image.tsx +28 -7
  46. package/src/product/product-list.tsx +44 -0
  47. package/src/product/product-price.tsx +77 -22
  48. package/src/product/product-sku.tsx +5 -5
  49. package/src/product/product-stock-badge.tsx +41 -28
  50. package/src/product/product-title.tsx +2 -3
  51. package/src/product/product-variant-picker.tsx +61 -0
  52. package/src/register/cash-count-input.tsx +85 -0
  53. package/src/register/closure-sheet.tsx +155 -0
  54. package/src/register/index.ts +12 -0
  55. package/src/register/movement-sheet.tsx +118 -0
  56. package/src/register/open-register-card.tsx +109 -0
  57. package/src/register/register-bar.helpers.ts +57 -0
  58. package/src/register/register-bar.tsx +85 -0
  59. package/src/register/register-column.tsx +117 -0
  60. package/src/register/register-count.tsx +330 -0
  61. package/src/register/register-open-close.tsx +52 -0
  62. package/src/register/register-panel.tsx +151 -0
  63. package/src/register/register-picker.tsx +60 -0
  64. package/src/register/register-summary.tsx +72 -0
  65. package/src/sale/cart-bar.tsx +18 -0
  66. package/src/sale/cart.tsx +66 -0
  67. package/src/sale/catalogue.tsx +131 -0
  68. package/src/sale/discount-form.tsx +85 -0
  69. package/src/sale/index.ts +9 -0
  70. package/src/sale/orders-list.tsx +66 -0
  71. package/src/sale/print-style.ts +11 -0
  72. package/src/sale/receipt.tsx +61 -0
  73. package/src/sale/sync-status.tsx +20 -0
  74. package/src/sale/tender.tsx +35 -0
  75. package/src/settings/connector-status.tsx +65 -0
  76. package/src/settings/index.ts +3 -0
  77. package/src/settings/settings-group.tsx +23 -0
  78. package/src/settings/settings-row.tsx +23 -0
  79. package/src/ui/accordion/index.tsx +59 -0
  80. package/src/ui/alert-dialog/index.tsx +91 -0
  81. package/src/ui/avatar/index.tsx +50 -0
  82. package/src/ui/badge/index.tsx +60 -0
  83. package/src/ui/button/index.tsx +90 -0
  84. package/src/ui/card/index.tsx +60 -0
  85. package/src/ui/checkbox/index.tsx +29 -0
  86. package/src/ui/collapsible/index.tsx +24 -0
  87. package/src/ui/combobox/index.tsx +98 -0
  88. package/src/ui/context-menu/index.tsx +159 -0
  89. package/src/ui/dialog/index.tsx +92 -0
  90. package/src/ui/dropdown-menu/index.tsx +161 -0
  91. package/src/ui/hover-card/index.tsx +31 -0
  92. package/src/ui/hstack/index.tsx +43 -0
  93. package/src/ui/icon/index.tsx +44 -0
  94. package/src/ui/icon/search-icon.tsx +9 -0
  95. package/src/ui/icon/svg-icon.tsx +36 -0
  96. package/src/ui/icon-button/index.tsx +58 -0
  97. package/src/ui/index.ts +99 -0
  98. package/src/ui/input/index.tsx +100 -0
  99. package/src/ui/label/index.tsx +26 -0
  100. package/src/ui/loader/index.tsx +37 -0
  101. package/src/ui/popover/index.tsx +31 -0
  102. package/src/ui/progress/index.tsx +28 -0
  103. package/src/ui/radio-group/index.tsx +38 -0
  104. package/src/ui/select/index.tsx +96 -0
  105. package/src/ui/separator/index.tsx +29 -0
  106. package/src/ui/slider/index.tsx +28 -0
  107. package/src/ui/switch/index.tsx +31 -0
  108. package/src/ui/table/index.tsx +59 -0
  109. package/src/ui/tabs/index.tsx +53 -0
  110. package/src/ui/text/index.tsx +36 -0
  111. package/src/ui/textarea/index.tsx +29 -0
  112. package/src/ui/toast/index.tsx +52 -0
  113. package/src/ui/toggle/index.tsx +69 -0
  114. package/src/ui/toggle-group/index.tsx +66 -0
  115. package/src/ui/tooltip/index.tsx +30 -0
  116. package/src/ui/vstack/index.tsx +43 -0
  117. package/src/uniwind-env.d.ts +9 -1
  118. package/src/__tests__/cart-line.test.tsx +0 -53
  119. package/src/__tests__/cart-panel.test.tsx +0 -55
  120. package/src/__tests__/cart-total.test.tsx +0 -60
  121. package/src/__tests__/customer-card.test.tsx +0 -47
  122. package/src/__tests__/customer-select.test.tsx +0 -33
  123. package/src/__tests__/filter-chip.test.tsx +0 -40
  124. package/src/__tests__/helpers.ts +0 -111
  125. package/src/__tests__/order-summary-line.test.tsx +0 -18
  126. package/src/__tests__/order-summary.test.tsx +0 -32
  127. package/src/__tests__/payment-method-card.test.tsx +0 -24
  128. package/src/__tests__/payment-selector.test.tsx +0 -23
  129. package/src/__tests__/product-card.test.tsx +0 -31
  130. package/src/__tests__/product-grid.test.tsx +0 -37
  131. package/src/__tests__/product-image.test.tsx +0 -54
  132. package/src/__tests__/product-price.test.tsx +0 -68
  133. package/src/__tests__/product-sku.test.tsx +0 -47
  134. package/src/__tests__/product-stock-badge.test.tsx +0 -58
  135. package/src/__tests__/product-title.test.tsx +0 -38
  136. package/src/__tests__/search-input.test.tsx +0 -22
@@ -1,111 +0,0 @@
1
- import type { TallyConnector, CustomerTraits } from '@tallyui/core';
2
- import { wooProductTraits } from '@tallyui/connector-woocommerce';
3
- import { medusaProductTraits } from '@tallyui/connector-medusa';
4
- import { products } from '@tallyui/mock-api/data';
5
- import { toWooProduct, toMedusaProduct } from '@tallyui/mock-api/transforms';
6
-
7
- /**
8
- * Sample WooCommerce product document for component tests.
9
- * Generated from the shared mock catalog.
10
- */
11
- export const wooDoc = toWooProduct(products[0], 1);
12
-
13
- /**
14
- * Sample MedusaJS product document for component tests.
15
- * Generated from the shared mock catalog.
16
- */
17
- export const medusaDoc = toMedusaProduct(products[0]);
18
-
19
- /**
20
- * Sample WooCommerce customer document for component tests.
21
- */
22
- export const wooCustomerDoc = {
23
- id: 1,
24
- first_name: 'Jane',
25
- last_name: 'Smith',
26
- email: 'jane@example.com',
27
- billing: {
28
- address_1: '123 Main St',
29
- city: 'Springfield',
30
- state: 'IL',
31
- postcode: '62701',
32
- },
33
- };
34
-
35
- /**
36
- * Sample MedusaJS customer document for component tests.
37
- */
38
- export const medusaCustomerDoc = {
39
- id: 'cus_01H',
40
- first_name: 'Jane',
41
- last_name: 'Smith',
42
- email: 'jane@example.com',
43
- addresses: [{
44
- address_1: '123 Main St',
45
- city: 'Springfield',
46
- province: 'IL',
47
- postal_code: '62701',
48
- }],
49
- };
50
-
51
- const wooCustomerTraits: CustomerTraits = {
52
- getId: (doc) => String(doc.id),
53
- getName: (doc) => [doc.first_name, doc.last_name].filter(Boolean).join(' ') || 'Guest',
54
- getEmail: (doc) => doc.email || undefined,
55
- getPhone: (doc) => doc.billing?.phone || undefined,
56
- getAddressSummary: (doc) => {
57
- const b = doc.billing;
58
- if (!b?.address_1) return undefined;
59
- return [b.address_1, b.city, b.state].filter(Boolean).join(', ');
60
- },
61
- };
62
-
63
- const medusaCustomerTraits: CustomerTraits = {
64
- getId: (doc) => doc.id,
65
- getName: (doc) => [doc.first_name, doc.last_name].filter(Boolean).join(' ') || 'Guest',
66
- getEmail: (doc) => doc.email || undefined,
67
- getPhone: (doc) => doc.phone || undefined,
68
- getAddressSummary: (doc) => {
69
- const a = doc.addresses?.[0];
70
- if (!a?.address_1) return undefined;
71
- return [a.address_1, a.city, a.province].filter(Boolean).join(', ');
72
- },
73
- };
74
-
75
- /**
76
- * Builds a minimal TallyConnector with real product traits
77
- * for either WooCommerce or Medusa.
78
- */
79
- export function createTestConnector(type: 'woo' | 'medusa'): TallyConnector {
80
- const traits = type === 'woo' ? wooProductTraits : medusaProductTraits;
81
-
82
- return {
83
- id: type,
84
- name: type === 'woo' ? 'WooCommerce' : 'MedusaJS',
85
- description: `Test ${type} connector`,
86
- auth: {
87
- type: 'none',
88
- fields: [],
89
- getHeaders: () => ({}),
90
- },
91
- schemas: {
92
- products: {
93
- version: 0,
94
- primaryKey: 'id',
95
- type: 'object',
96
- properties: { id: { type: 'string', maxLength: 100 } },
97
- required: ['id'],
98
- },
99
- },
100
- traits: {
101
- product: traits,
102
- customer: type === 'woo' ? wooCustomerTraits : medusaCustomerTraits,
103
- },
104
- sync: {
105
- products: {
106
- fetchAllIds: async () => [],
107
- fetchByIds: async () => [],
108
- },
109
- },
110
- };
111
- }
@@ -1,18 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { OrderSummaryLine } from '../checkout/order-summary-line';
4
-
5
- describe('OrderSummaryLine', () => {
6
- it('renders label and amount', () => {
7
- render(<OrderSummaryLine label="Subtotal" amount="$599.99" />);
8
- expect(screen.getByText('Subtotal')).toBeDefined();
9
- expect(screen.getByText('$599.99')).toBeDefined();
10
- });
11
-
12
- it('applies bold variant', () => {
13
- const { container } = render(
14
- <OrderSummaryLine label="Total" amount="$659.99" bold />
15
- );
16
- expect(container).toBeDefined();
17
- });
18
- });
@@ -1,32 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { Text } from 'react-native';
4
- import { OrderSummary } from '../checkout/order-summary';
5
-
6
- describe('OrderSummary', () => {
7
- it('renders subtotal, tax, and total lines', () => {
8
- render(
9
- <OrderSummary subtotal="$1199.98" tax="$120.00" taxLabel="GST" total="$1319.98" />
10
- );
11
- expect(screen.getByText('Subtotal')).toBeDefined();
12
- expect(screen.getByText('$1199.98')).toBeDefined();
13
- expect(screen.getByText('GST')).toBeDefined();
14
- expect(screen.getByText('$120.00')).toBeDefined();
15
- expect(screen.getByText('Total')).toBeDefined();
16
- expect(screen.getByText('$1319.98')).toBeDefined();
17
- });
18
-
19
- it('renders header slot', () => {
20
- render(
21
- <OrderSummary subtotal="$100.00" total="$100.00" header={<Text>Customer: Jane</Text>} />
22
- );
23
- expect(screen.getByText('Customer: Jane')).toBeDefined();
24
- });
25
-
26
- it('renders payment info', () => {
27
- render(
28
- <OrderSummary subtotal="$100.00" total="$100.00" payments={[{ label: 'Cash', amount: '$100.00' }]} />
29
- );
30
- expect(screen.getByText('Cash')).toBeDefined();
31
- });
32
- });
@@ -1,24 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import { PaymentMethodCard } from '../checkout/payment-method-card';
4
-
5
- describe('PaymentMethodCard', () => {
6
- it('renders the method label', () => {
7
- render(<PaymentMethodCard label="Credit Card" selected={false} onPress={() => {}} />);
8
- expect(screen.getByText('Credit Card')).toBeDefined();
9
- });
10
-
11
- it('calls onPress when tapped', () => {
12
- const onPress = vi.fn();
13
- render(<PaymentMethodCard label="Cash" selected={false} onPress={onPress} />);
14
- fireEvent.click(screen.getByText('Cash'));
15
- expect(onPress).toHaveBeenCalled();
16
- });
17
-
18
- it('shows selected state visually', () => {
19
- const { container } = render(
20
- <PaymentMethodCard label="Cash" selected={true} onPress={() => {}} />
21
- );
22
- expect(container).toBeDefined();
23
- });
24
- });
@@ -1,23 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import { PaymentSelector } from '../checkout/payment-selector';
4
-
5
- describe('PaymentSelector', () => {
6
- const methods = [
7
- { id: 'cash', label: 'Cash' },
8
- { id: 'card', label: 'Credit Card' },
9
- ];
10
-
11
- it('renders all payment methods', () => {
12
- render(<PaymentSelector methods={methods} selected="cash" onSelect={() => {}} />);
13
- expect(screen.getByText('Cash')).toBeDefined();
14
- expect(screen.getByText('Credit Card')).toBeDefined();
15
- });
16
-
17
- it('calls onSelect when a method is tapped', () => {
18
- const onSelect = vi.fn();
19
- render(<PaymentSelector methods={methods} selected="cash" onSelect={onSelect} />);
20
- fireEvent.click(screen.getByText('Credit Card'));
21
- expect(onSelect).toHaveBeenCalledWith('card');
22
- });
23
- });
@@ -1,31 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import { ConnectorProvider } from '@tallyui/core';
4
- import { ProductCard } from '../product/product-card';
5
- import { createTestConnector, wooDoc } from './helpers';
6
-
7
- describe('ProductCard', () => {
8
- it('renders product name and price', () => {
9
- const connector = createTestConnector('woo');
10
- render(
11
- <ConnectorProvider connector={connector}>
12
- <ProductCard doc={wooDoc} />
13
- </ConnectorProvider>
14
- );
15
- expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
16
- expect(screen.getByText('$1299.00')).toBeDefined();
17
- });
18
-
19
- it('calls onPress when tapped', () => {
20
- const onPress = vi.fn();
21
- const connector = createTestConnector('woo');
22
- render(
23
- <ConnectorProvider connector={connector}>
24
- <ProductCard doc={wooDoc} onPress={onPress} />
25
- </ConnectorProvider>
26
- );
27
- // Click on the product name text element
28
- fireEvent.click(screen.getByText('Espresso Machine Pro'));
29
- expect(onPress).toHaveBeenCalled();
30
- });
31
- });
@@ -1,37 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { Text } from 'react-native';
4
- import { ConnectorProvider } from '@tallyui/core';
5
- import { ProductGrid } from '../product/product-grid';
6
- import { createTestConnector, wooDoc } from './helpers';
7
-
8
- describe('ProductGrid', () => {
9
- it('renders items via renderItem', () => {
10
- const connector = createTestConnector('woo');
11
- const items = [{ ...wooDoc, id: 1 }, { ...wooDoc, id: 2, name: 'Grinder Pro' }];
12
- render(
13
- <ConnectorProvider connector={connector}>
14
- <ProductGrid
15
- items={items}
16
- renderItem={(doc) => <Text key={doc.id}>{doc.name}</Text>}
17
- />
18
- </ConnectorProvider>
19
- );
20
- expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
21
- expect(screen.getByText('Grinder Pro')).toBeDefined();
22
- });
23
-
24
- it('renders emptyState when items is empty', () => {
25
- const connector = createTestConnector('woo');
26
- render(
27
- <ConnectorProvider connector={connector}>
28
- <ProductGrid
29
- items={[]}
30
- renderItem={() => null}
31
- emptyState={<Text>No products</Text>}
32
- />
33
- </ConnectorProvider>
34
- );
35
- expect(screen.getByText('No products')).toBeDefined();
36
- });
37
- });
@@ -1,54 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render } from '@testing-library/react';
3
- import { ConnectorProvider } from '@tallyui/core';
4
- import { ProductImage } from '../product/product-image';
5
- import { createTestConnector, wooDoc, medusaDoc } from './helpers';
6
-
7
- describe('ProductImage', () => {
8
- it('renders an image for WooCommerce product', () => {
9
- const connector = createTestConnector('woo');
10
- const { container } = render(
11
- <ConnectorProvider connector={connector}>
12
- <ProductImage doc={wooDoc} />
13
- </ConnectorProvider>
14
- );
15
- const img = container.querySelector('img');
16
- expect(img).not.toBeNull();
17
- expect(img?.getAttribute('src')).toBe('https://picsum.photos/seed/espresso-machine/800/800');
18
- });
19
-
20
- it('renders an image for Medusa product (uses thumbnail)', () => {
21
- const connector = createTestConnector('medusa');
22
- const { container } = render(
23
- <ConnectorProvider connector={connector}>
24
- <ProductImage doc={medusaDoc} />
25
- </ConnectorProvider>
26
- );
27
- const img = container.querySelector('img');
28
- expect(img).not.toBeNull();
29
- expect(img?.getAttribute('src')).toBe('https://picsum.photos/seed/espresso-machine/800/800');
30
- });
31
-
32
- it('renders nothing when no image URL is available', () => {
33
- const connector = createTestConnector('woo');
34
- const { container } = render(
35
- <ConnectorProvider connector={connector}>
36
- <ProductImage doc={{}} />
37
- </ConnectorProvider>
38
- );
39
- const img = container.querySelector('img');
40
- expect(img).toBeNull();
41
- });
42
-
43
- it('renders with custom size prop without crashing', () => {
44
- const connector = createTestConnector('woo');
45
- const { container } = render(
46
- <ConnectorProvider connector={connector}>
47
- <ProductImage doc={wooDoc} size={120} />
48
- </ConnectorProvider>
49
- );
50
- const img = container.querySelector('img');
51
- expect(img).not.toBeNull();
52
- expect(img?.getAttribute('src')).toBe('https://picsum.photos/seed/espresso-machine/800/800');
53
- });
54
- });
@@ -1,68 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { ConnectorProvider } from '@tallyui/core';
4
- import { ProductPrice } from '../product/product-price';
5
- import { createTestConnector, wooDoc, medusaDoc } from './helpers';
6
-
7
- describe('ProductPrice', () => {
8
- it('renders WooCommerce price with default $ symbol', () => {
9
- const connector = createTestConnector('woo');
10
- render(
11
- <ConnectorProvider connector={connector}>
12
- <ProductPrice doc={wooDoc} />
13
- </ConnectorProvider>
14
- );
15
- expect(screen.getByText('$1299.00')).toBeDefined();
16
- });
17
-
18
- it('renders Medusa price (converted from cents)', () => {
19
- const connector = createTestConnector('medusa');
20
- render(
21
- <ConnectorProvider connector={connector}>
22
- <ProductPrice doc={medusaDoc} />
23
- </ConnectorProvider>
24
- );
25
- expect(screen.getByText('$1299.00')).toBeDefined();
26
- });
27
-
28
- it('renders custom currency symbol', () => {
29
- const connector = createTestConnector('woo');
30
- render(
31
- <ConnectorProvider connector={connector}>
32
- <ProductPrice doc={wooDoc} currencySymbol="€" />
33
- </ConnectorProvider>
34
- );
35
- expect(screen.getByText('€1299.00')).toBeDefined();
36
- });
37
-
38
- it('renders dash when price is missing', () => {
39
- const connector = createTestConnector('woo');
40
- render(
41
- <ConnectorProvider connector={connector}>
42
- <ProductPrice doc={{}} />
43
- </ConnectorProvider>
44
- );
45
- expect(screen.getByText('-')).toBeDefined();
46
- });
47
-
48
- it('shows sale price with "was" indicator for on-sale WooCommerce product', () => {
49
- const connector = createTestConnector('woo');
50
- const saleDoc = {
51
- ...wooDoc,
52
- price: '499.99',
53
- sale_price: '499.99',
54
- regular_price: '599.99',
55
- on_sale: true,
56
- };
57
- render(
58
- <ConnectorProvider connector={connector}>
59
- <ProductPrice doc={saleDoc} />
60
- </ConnectorProvider>
61
- );
62
- // The component should show the sale price and "was" regular price
63
- const el = screen.getByText(/499\.99/);
64
- expect(el).toBeDefined();
65
- expect(el.textContent).toContain('was');
66
- expect(el.textContent).toContain('599.99');
67
- });
68
- });
@@ -1,47 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { ConnectorProvider } from '@tallyui/core';
4
- import { ProductSku } from '../product/product-sku';
5
- import { createTestConnector, wooDoc, medusaDoc } from './helpers';
6
-
7
- describe('ProductSku', () => {
8
- it('renders WooCommerce SKU', () => {
9
- const connector = createTestConnector('woo');
10
- render(
11
- <ConnectorProvider connector={connector}>
12
- <ProductSku doc={wooDoc} />
13
- </ConnectorProvider>
14
- );
15
- expect(screen.getByText('EQ-ESP-001')).toBeDefined();
16
- });
17
-
18
- it('renders Medusa SKU from variant', () => {
19
- const connector = createTestConnector('medusa');
20
- render(
21
- <ConnectorProvider connector={connector}>
22
- <ProductSku doc={medusaDoc} />
23
- </ConnectorProvider>
24
- );
25
- expect(screen.getByText('EQ-ESP-001')).toBeDefined();
26
- });
27
-
28
- it('renders fallback when SKU is missing', () => {
29
- const connector = createTestConnector('woo');
30
- render(
31
- <ConnectorProvider connector={connector}>
32
- <ProductSku doc={{}} />
33
- </ConnectorProvider>
34
- );
35
- expect(screen.getByText('—')).toBeDefined();
36
- });
37
-
38
- it('renders custom fallback text', () => {
39
- const connector = createTestConnector('woo');
40
- render(
41
- <ConnectorProvider connector={connector}>
42
- <ProductSku doc={{}} fallback="N/A" />
43
- </ConnectorProvider>
44
- );
45
- expect(screen.getByText('N/A')).toBeDefined();
46
- });
47
- });
@@ -1,58 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { ConnectorProvider } from '@tallyui/core';
4
- import { ProductStockBadge } from '../product/product-stock-badge';
5
- import { createTestConnector, wooDoc, medusaDoc } from './helpers';
6
-
7
- describe('ProductStockBadge', () => {
8
- it('renders "In Stock" for WooCommerce in-stock product', () => {
9
- const connector = createTestConnector('woo');
10
- render(
11
- <ConnectorProvider connector={connector}>
12
- <ProductStockBadge doc={wooDoc} />
13
- </ConnectorProvider>
14
- );
15
- expect(screen.getByText('In Stock')).toBeDefined();
16
- });
17
-
18
- it('renders "In Stock" for Medusa product with inventory', () => {
19
- const connector = createTestConnector('medusa');
20
- render(
21
- <ConnectorProvider connector={connector}>
22
- <ProductStockBadge doc={medusaDoc} />
23
- </ConnectorProvider>
24
- );
25
- expect(screen.getByText('In Stock')).toBeDefined();
26
- });
27
-
28
- it('renders "Out of Stock" for out-of-stock product', () => {
29
- const connector = createTestConnector('woo');
30
- const outOfStockDoc = { ...wooDoc, stock_status: 'outofstock', stock_quantity: 0 };
31
- render(
32
- <ConnectorProvider connector={connector}>
33
- <ProductStockBadge doc={outOfStockDoc} />
34
- </ConnectorProvider>
35
- );
36
- expect(screen.getByText('Out of Stock')).toBeDefined();
37
- });
38
-
39
- it('shows quantity when showQuantity is true', () => {
40
- const connector = createTestConnector('woo');
41
- render(
42
- <ConnectorProvider connector={connector}>
43
- <ProductStockBadge doc={wooDoc} showQuantity />
44
- </ConnectorProvider>
45
- );
46
- expect(screen.getByText('In Stock (12)')).toBeDefined();
47
- });
48
-
49
- it('renders "Unknown" when stock status is missing', () => {
50
- const connector = createTestConnector('woo');
51
- render(
52
- <ConnectorProvider connector={connector}>
53
- <ProductStockBadge doc={{}} />
54
- </ConnectorProvider>
55
- );
56
- expect(screen.getByText('Unknown')).toBeDefined();
57
- });
58
- });
@@ -1,38 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import { ConnectorProvider } from '@tallyui/core';
4
- import { ProductTitle } from '../product/product-title';
5
- import { createTestConnector, wooDoc, medusaDoc } from './helpers';
6
-
7
- describe('ProductTitle', () => {
8
- it('renders the WooCommerce product name', () => {
9
- const connector = createTestConnector('woo');
10
- render(
11
- <ConnectorProvider connector={connector}>
12
- <ProductTitle doc={wooDoc} />
13
- </ConnectorProvider>
14
- );
15
- expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
16
- });
17
-
18
- it('renders the Medusa product title', () => {
19
- const connector = createTestConnector('medusa');
20
- render(
21
- <ConnectorProvider connector={connector}>
22
- <ProductTitle doc={medusaDoc} />
23
- </ConnectorProvider>
24
- );
25
- expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
26
- });
27
-
28
- it('renders empty string gracefully for missing name', () => {
29
- const connector = createTestConnector('woo');
30
- const { container } = render(
31
- <ConnectorProvider connector={connector}>
32
- <ProductTitle doc={{}} />
33
- </ConnectorProvider>
34
- );
35
- // Should render without crashing
36
- expect(container).toBeDefined();
37
- });
38
- });
@@ -1,22 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import { SearchInput } from '../input/search-input';
4
-
5
- describe('SearchInput', () => {
6
- it('renders with placeholder text', () => {
7
- render(<SearchInput value="" onChangeText={() => {}} placeholder="Search products..." />);
8
- expect(screen.getByPlaceholderText('Search products...')).toBeDefined();
9
- });
10
-
11
- it('displays the current value', () => {
12
- render(<SearchInput value="espresso" onChangeText={() => {}} />);
13
- expect(screen.getByDisplayValue('espresso')).toBeDefined();
14
- });
15
-
16
- it('calls onChangeText when text changes', () => {
17
- const onChangeText = vi.fn();
18
- render(<SearchInput value="" onChangeText={onChangeText} />);
19
- fireEvent.change(screen.getByPlaceholderText('Search...'), { target: { value: 'latte' } });
20
- expect(onChangeText).toHaveBeenCalledWith('latte');
21
- });
22
- });