@shopify/ui-extensions-tester 0.0.1-alpha.0 → 2026.4.0-rc.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.
Files changed (136) hide show
  1. package/README.md +64 -14
  2. package/admin.esnext +1 -0
  3. package/admin.js +1 -0
  4. package/admin.mjs +1 -0
  5. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +15 -0
  6. package/build/cjs/admin/factories.js +323 -0
  7. package/build/cjs/admin/index.js +70 -0
  8. package/build/cjs/api-version.js +22 -0
  9. package/build/cjs/checkout/factories.js +412 -0
  10. package/build/cjs/checkout/index.js +162 -0
  11. package/build/cjs/customer-account/factories.js +235 -0
  12. package/build/cjs/customer-account/index.js +89 -0
  13. package/build/cjs/fetch-polyfills.js +193 -0
  14. package/build/cjs/index.js +467 -0
  15. package/build/cjs/mocks/i18n.js +21 -0
  16. package/build/cjs/mocks/money.js +16 -0
  17. package/build/cjs/mocks/signals.js +34 -0
  18. package/build/cjs/mocks/target-apis.js +37 -0
  19. package/build/cjs/navigation.js +56 -0
  20. package/build/cjs/point-of-sale/factories.js +510 -0
  21. package/build/cjs/point-of-sale/index.js +85 -0
  22. package/build/cjs/targets.js +36 -0
  23. package/build/esm/_virtual/_rollupPluginBabelHelpers.mjs +10 -0
  24. package/build/esm/admin/factories.mjs +318 -0
  25. package/build/esm/admin/index.mjs +65 -0
  26. package/build/esm/api-version.mjs +18 -0
  27. package/build/esm/checkout/factories.mjs +408 -0
  28. package/build/esm/checkout/index.mjs +153 -0
  29. package/build/esm/customer-account/factories.mjs +231 -0
  30. package/build/esm/customer-account/index.mjs +83 -0
  31. package/build/esm/fetch-polyfills.mjs +188 -0
  32. package/build/esm/index.mjs +440 -0
  33. package/build/esm/mocks/i18n.mjs +17 -0
  34. package/build/esm/mocks/money.mjs +12 -0
  35. package/build/esm/mocks/signals.mjs +29 -0
  36. package/build/esm/mocks/target-apis.mjs +33 -0
  37. package/build/esm/navigation.mjs +51 -0
  38. package/build/esm/point-of-sale/factories.mjs +506 -0
  39. package/build/esm/point-of-sale/index.mjs +79 -0
  40. package/build/esm/targets.mjs +29 -0
  41. package/build/esnext/_virtual/_rollupPluginBabelHelpers.esnext +10 -0
  42. package/build/esnext/admin/factories.esnext +318 -0
  43. package/build/esnext/admin/index.esnext +65 -0
  44. package/build/esnext/api-version.esnext +18 -0
  45. package/build/esnext/checkout/factories.esnext +408 -0
  46. package/build/esnext/checkout/index.esnext +153 -0
  47. package/build/esnext/customer-account/factories.esnext +231 -0
  48. package/build/esnext/customer-account/index.esnext +83 -0
  49. package/build/esnext/fetch-polyfills.esnext +188 -0
  50. package/build/esnext/index.esnext +440 -0
  51. package/build/esnext/mocks/i18n.esnext +17 -0
  52. package/build/esnext/mocks/money.esnext +12 -0
  53. package/build/esnext/mocks/signals.esnext +29 -0
  54. package/build/esnext/mocks/target-apis.esnext +33 -0
  55. package/build/esnext/navigation.esnext +51 -0
  56. package/build/esnext/point-of-sale/factories.esnext +506 -0
  57. package/build/esnext/point-of-sale/index.esnext +79 -0
  58. package/build/esnext/targets.esnext +29 -0
  59. package/build/ts/admin/factories.d.ts +19 -0
  60. package/build/ts/admin/factories.d.ts.map +1 -0
  61. package/build/ts/admin/index.d.ts +31 -0
  62. package/build/ts/admin/index.d.ts.map +1 -0
  63. package/build/ts/api-version.d.ts +11 -0
  64. package/build/ts/api-version.d.ts.map +1 -0
  65. package/build/ts/checkout/factories.d.ts +10 -0
  66. package/build/ts/checkout/factories.d.ts.map +1 -0
  67. package/build/ts/checkout/index.d.ts +53 -0
  68. package/build/ts/checkout/index.d.ts.map +1 -0
  69. package/build/ts/customer-account/factories.d.ts +8 -0
  70. package/build/ts/customer-account/factories.d.ts.map +1 -0
  71. package/build/ts/customer-account/index.d.ts +21 -0
  72. package/build/ts/customer-account/index.d.ts.map +1 -0
  73. package/build/ts/disposable.d.ts +20 -0
  74. package/build/ts/fetch-polyfills.d.ts +19 -0
  75. package/build/ts/fetch-polyfills.d.ts.map +1 -0
  76. package/build/ts/index.d.ts +138 -0
  77. package/build/ts/index.d.ts.map +1 -0
  78. package/build/ts/mocks/i18n.d.ts +14 -0
  79. package/build/ts/mocks/i18n.d.ts.map +1 -0
  80. package/build/ts/mocks/money.d.ts +9 -0
  81. package/build/ts/mocks/money.d.ts.map +1 -0
  82. package/build/ts/mocks/signals.d.ts +19 -0
  83. package/build/ts/mocks/signals.d.ts.map +1 -0
  84. package/build/ts/mocks/target-apis.d.ts +15 -0
  85. package/build/ts/mocks/target-apis.d.ts.map +1 -0
  86. package/build/ts/navigation.d.ts +41 -0
  87. package/build/ts/navigation.d.ts.map +1 -0
  88. package/build/ts/point-of-sale/factories.d.ts +20 -0
  89. package/build/ts/point-of-sale/factories.d.ts.map +1 -0
  90. package/build/ts/point-of-sale/index.d.ts +30 -0
  91. package/build/ts/point-of-sale/index.d.ts.map +1 -0
  92. package/build/ts/targets.d.ts +27 -0
  93. package/build/ts/targets.d.ts.map +1 -0
  94. package/build/tsconfig.tsbuildinfo +1 -0
  95. package/checkout.esnext +1 -0
  96. package/checkout.js +1 -0
  97. package/checkout.mjs +1 -0
  98. package/customer-account.esnext +1 -0
  99. package/customer-account.js +1 -0
  100. package/customer-account.mjs +1 -0
  101. package/index.esnext +1 -0
  102. package/index.js +1 -0
  103. package/index.mjs +1 -0
  104. package/package.json +84 -2
  105. package/point-of-sale.esnext +1 -0
  106. package/point-of-sale.js +1 -0
  107. package/point-of-sale.mjs +1 -0
  108. package/src/admin/README.md +78 -0
  109. package/src/admin/factories.ts +380 -0
  110. package/src/admin/index.ts +85 -0
  111. package/src/api-version.ts +23 -0
  112. package/src/checkout/README.md +152 -0
  113. package/src/checkout/factories.ts +482 -0
  114. package/src/checkout/index.ts +174 -0
  115. package/src/customer-account/README.md +86 -0
  116. package/src/customer-account/factories.ts +272 -0
  117. package/src/customer-account/index.ts +90 -0
  118. package/src/disposable.d.ts +20 -0
  119. package/src/fetch-polyfills.ts +222 -0
  120. package/src/index.ts +551 -0
  121. package/src/mocks/i18n.ts +15 -0
  122. package/src/mocks/money.ts +7 -0
  123. package/src/mocks/signals.ts +37 -0
  124. package/src/mocks/target-apis.ts +56 -0
  125. package/src/navigation.ts +72 -0
  126. package/src/point-of-sale/README.md +100 -0
  127. package/src/point-of-sale/factories.ts +581 -0
  128. package/src/point-of-sale/index.ts +92 -0
  129. package/src/targets.ts +68 -0
  130. package/src/tests/admin-factories.test.ts +31 -0
  131. package/src/tests/fetch.test.ts +139 -0
  132. package/src/tests/fixtures/test-module.ts +1 -0
  133. package/src/tests/getExtension.test.ts +259 -0
  134. package/src/tests/helpers.ts +140 -0
  135. package/src/tests/navigation.test.ts +130 -0
  136. package/src/tests/setUpExtension.test.ts +52 -0
package/README.md CHANGED
@@ -14,6 +14,7 @@ This testing library provides strongly typed mocks of the extension API--like th
14
14
  ## 📋 Recommendations
15
15
 
16
16
  - **TypeScript** — we recommend TypeScript to enforce API compliance against mock objects
17
+ - **Node.js ≥ 22.0.0** and **TypeScript ≥ 5.2** — to use ([Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management))
17
18
  - **@testing-library/preact** — if your extension uses [Preact](https://preactjs.com/), we recommend installing [`@testing-library/preact`](https://preactjs.com/guide/v10/preact-testing-library/) for its `fireEvent` and `waitFor` helpers
18
19
 
19
20
  ## 📦 Installation
@@ -72,7 +73,7 @@ Your extension's own `package.json` (inside `extensions/my-extension/`) already
72
73
  "devDependencies": {
73
74
  "@shopify/ui-extensions-tester": "latest",
74
75
  "@testing-library/preact": "^3.2.0",
75
- "typescript": "^5.0.0",
76
+ "typescript": "^5.2.0",
76
77
  "vitest": "^3.0.0"
77
78
  }
78
79
  }
@@ -144,7 +145,34 @@ The path must match the target you pass to `getExtension()`.
144
145
 
145
146
  ## 🏊‍♀️ Getting started
146
147
 
147
- Every test file follows the same pattern: create an extension harness, call `extension.setUp()` before each test, call `extension.tearDown()` after.
148
+ Every test file follows the same pattern:
149
+ create an extension harness, set it up before
150
+ each test, and tear it down after.
151
+
152
+ ### Quick start with `using` (Node ≥ 22.0.0)
153
+
154
+ If your runtime supports
155
+ [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management),
156
+ use `setUpExtension` for zero-boilerplate
157
+ setup and automatic teardown:
158
+
159
+ ```ts
160
+ import {setUpExtension} from '@shopify/ui-extensions-tester';
161
+
162
+ test('rendering the extension', async () => {
163
+ using extension = setUpExtension(
164
+ 'purchase.checkout.block.render',
165
+ );
166
+ await extension.render();
167
+ // tearDown() is called automatically at the end of the block
168
+ });
169
+ ```
170
+
171
+ ### Classic setup
172
+
173
+ Alternatively, create the harness once and
174
+ manage the lifecycle with `beforeEach` /
175
+ `afterEach`:
148
176
 
149
177
  ```ts
150
178
  import {getExtension} from '@shopify/ui-extensions-tester';
@@ -339,25 +367,31 @@ Each surface exports some helpers:
339
367
 
340
368
  Exports from `@shopify/ui-extensions-tester`:
341
369
 
342
- ### `getExtension(target, options?)`
370
+ ### `setUpExtension(target, options?)`
371
+
372
+ Sets up an extension for testing and returns a
373
+ disposable object that supports automatic
374
+ teardown with the `using` keyword:
375
+
376
+ ```ts
377
+ test('example', async () => {
378
+ using extension = setUpExtension(
379
+ 'purchase.checkout.block.render',
380
+ );
381
+ await extension.render();
382
+ // tearDown() called automatically
383
+ });
384
+ ```
343
385
 
344
- Returns an extension test harness for the given target. It reads `shopify.extension.toml`, finds the module for the given target, and provides helpers to mock the environment and render the extension. It locates `shopify.extension.toml` by walking up from the calling test file's directory, and falls back to searching `extensions/` under the current working directory.
386
+ It reads `shopify.extension.toml`, finds the module for the given target, and provides helpers to mock the environment and render the extension. It locates `shopify.extension.toml` by walking up from the calling test file's directory, and falls back to searching `extensions/` under the current working directory. Results are cached: calling `getExtension` twice with the same target and the same resolved TOML returns the same instance.
345
387
 
346
388
  | Option | Type | Default | Description |
347
389
  | ----------------- | -------- | ----------------------------- | ---------------------------------------------------------- |
348
390
  | `configSearchDir` | `string` | calling test file's directory | Directory to start searching for `shopify.extension.toml`. |
349
391
 
350
- By default `getExtension` walks up from the test file's directory to find `shopify.extension.toml`.
351
-
352
- **Returns** an `Extension<T>` object with the following members:
392
+ By default, it walks up from the test file's directory to find `shopify.extension.toml`.
353
393
 
354
- #### `extension.setUp()`
355
-
356
- Sets up an extension environment for testing. Creates a mock `shopify` global with some defaults.
357
-
358
- #### `extension.tearDown()`
359
-
360
- Tears down the extension environment. Resets the `shopify` global and clears `document.body`.
394
+ **Returns** an `Extension` object with the following members:
361
395
 
362
396
  #### `extension.render()`
363
397
 
@@ -402,6 +436,22 @@ extension.navigation.currentEntry =
402
436
 
403
437
  Assigning to `extension.navigation` also updates `globalThis.navigation`, so extension code that calls `navigation.navigate()` directly will use the mock.
404
438
 
439
+ ### `getExtension(target, options?)`
440
+
441
+ > ⚠️ Prefer [`setUpExtension`](#setupextensiontarget-options) on Node ≥ 22.0.0. Use `getExtension` only if your runtime does not support [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management).
442
+
443
+ Accepts the same arguments as `setUpExtension`. You must call `extension.setUp()` and `extension.tearDown()` explicitly.
444
+
445
+ **Returns** an `Extension` object with the following additional members:
446
+
447
+ #### `extension.setUp()`
448
+
449
+ Sets up an extension environment for testing. Creates a mock `shopify` global with some defaults.
450
+
451
+ #### `extension.tearDown()`
452
+
453
+ Tears down the extension environment. Resets the `shopify` global and clears `document.body`.
454
+
405
455
  ### `createNavigationHistoryEntry(options?)`
406
456
 
407
457
  Creates a [`NavigationHistoryEntry`](https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry) for mocking `navigation.currentEntry` or other navigation values.
package/admin.esnext ADDED
@@ -0,0 +1 @@
1
+ export * from "./build/esnext/admin/index.esnext";
package/admin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require("./build/cjs/admin/index.js");
package/admin.mjs ADDED
@@ -0,0 +1 @@
1
+ export * from "./build/esm/admin/index.mjs";
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ function _classPrivateFieldLooseBase(e, t) {
6
+ if (!{}.hasOwnProperty.call(e, t)) throw new TypeError("attempted to use private field on non-instance");
7
+ return e;
8
+ }
9
+ var id = 0;
10
+ function _classPrivateFieldLooseKey(e) {
11
+ return "__private_" + id++ + "_" + e;
12
+ }
13
+
14
+ exports.classPrivateFieldLooseBase = _classPrivateFieldLooseBase;
15
+ exports.classPrivateFieldLooseKey = _classPrivateFieldLooseKey;
@@ -0,0 +1,323 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var signals = require('../mocks/signals.js');
6
+ var i18n = require('../mocks/i18n.js');
7
+ var index = require('./index.js');
8
+
9
+ /**
10
+ * Extracts the API type for a given admin extension target directly from the
11
+ * implementation's `ExtensionTargets` interface.
12
+ *
13
+ * Properties prefixed with `__` are private internal APIs and are excluded
14
+ * from the mock type so they cannot be relied on in test suites.
15
+ */
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Derived types — not directly exported from the admin surface barrel
19
+ // ---------------------------------------------------------------------------
20
+
21
+ function gidFromTarget(target) {
22
+ const resource = target.split('.')[1].replace(/-details$|-index$|-fulfilled-card$|-purchase-option$/, '').split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join('');
23
+ return `gid://shopify/${resource}/1`;
24
+ }
25
+ function createData(selected = []) {
26
+ return {
27
+ selected
28
+ };
29
+ }
30
+ function createNavigation() {
31
+ return {
32
+ navigate: () => {}
33
+ };
34
+ }
35
+ function createConfigApp() {
36
+ return {
37
+ launchUrl: 'https://mock-app.test/launch',
38
+ applicationUrl: 'https://mock-app.test'
39
+ };
40
+ }
41
+ function createMockStandardApi(target) {
42
+ return {
43
+ extension: {
44
+ target
45
+ },
46
+ auth: {
47
+ idToken: async () => 'mock-id-token'
48
+ },
49
+ i18n: i18n.createMockI18n(),
50
+ intents: {
51
+ launchUrl: undefined,
52
+ invoke: async () => ({
53
+ complete: Promise.resolve({
54
+ code: 'closed'
55
+ })
56
+ })
57
+ },
58
+ storage: index.createStorage(),
59
+ query: async () => ({
60
+ data: undefined
61
+ })
62
+ };
63
+ }
64
+ function createMockStandardRenderingApi(target) {
65
+ return {
66
+ ...createMockStandardApi(target),
67
+ resourcePicker: async () => undefined,
68
+ picker: async () => ({
69
+ selected: Promise.resolve(undefined)
70
+ })
71
+ };
72
+ }
73
+ function createMockBlockApi(target) {
74
+ return {
75
+ ...createMockStandardRenderingApi(target),
76
+ data: createData([{
77
+ id: gidFromTarget(target)
78
+ }]),
79
+ navigation: createNavigation()
80
+ };
81
+ }
82
+ function createMockActionApi(target) {
83
+ return {
84
+ ...createMockStandardRenderingApi(target),
85
+ close: () => {},
86
+ data: createData([{
87
+ id: gidFromTarget(target)
88
+ }])
89
+ };
90
+ }
91
+
92
+ // ---------------------------------------------------------------------------
93
+ // Group factory functions — each composes the correct API for a target group
94
+ // ---------------------------------------------------------------------------
95
+
96
+ function createPrintActionMock(target) {
97
+ return {
98
+ ...createMockStandardRenderingApi(target),
99
+ data: createData()
100
+ };
101
+ }
102
+ function createShouldRenderMock(target) {
103
+ return {
104
+ ...createMockStandardApi(target),
105
+ data: createData()
106
+ };
107
+ }
108
+ function createProductDetailsConfigMock(target) {
109
+ return {
110
+ ...createMockBlockApi(target),
111
+ data: {
112
+ selected: [],
113
+ product: {
114
+ id: 'gid://shopify/Product/1',
115
+ title: 'Mock Product',
116
+ handle: 'mock-product',
117
+ status: 'ACTIVE',
118
+ totalVariants: 1,
119
+ totalInventory: 10,
120
+ hasOnlyDefaultVariant: true,
121
+ onlineStoreUrl: 'https://mock-shop.myshopify.com/products/mock-product',
122
+ options: [],
123
+ productType: '',
124
+ productComponents: []
125
+ },
126
+ app: createConfigApp()
127
+ }
128
+ };
129
+ }
130
+ function createProductVariantDetailsConfigMock(target) {
131
+ return {
132
+ ...createMockBlockApi(target),
133
+ data: {
134
+ selected: [],
135
+ variant: {
136
+ id: 'gid://shopify/ProductVariant/1',
137
+ sku: 'MOCK-SKU',
138
+ barcode: '',
139
+ title: 'Default',
140
+ displayName: 'Mock Product - Default',
141
+ price: '0.00',
142
+ compareAtPrice: '0.00',
143
+ taxable: true,
144
+ taxCode: '',
145
+ weight: 0,
146
+ selectedOptions: [],
147
+ productVariantComponents: []
148
+ },
149
+ app: createConfigApp()
150
+ }
151
+ };
152
+ }
153
+ function createDiscountFunctionSettingsMock(target) {
154
+ return {
155
+ ...createMockStandardRenderingApi(target),
156
+ navigation: createNavigation(),
157
+ applyMetafieldChange: async () => index.createResult('applyMetafieldChange'),
158
+ data: {
159
+ id: 'gid://shopify/DiscountAutomaticApp/1',
160
+ metafields: []
161
+ },
162
+ discounts: {
163
+ discountClasses: signals.createReadonlySignalLike([]),
164
+ updateDiscountClasses: () => index.createResult('updateDiscountClasses'),
165
+ discountMethod: signals.createReadonlySignalLike('automatic')
166
+ }
167
+ };
168
+ }
169
+ function createOrderRoutingRuleMock(target) {
170
+ return {
171
+ ...createMockStandardRenderingApi(target),
172
+ applyMetafieldsChange: () => {},
173
+ data: {
174
+ rule: {
175
+ label: 'Mock Routing Rule',
176
+ description: 'A mock order routing rule',
177
+ id: 'gid://shopify/DeliveryCustomization/1',
178
+ metafields: []
179
+ }
180
+ }
181
+ };
182
+ }
183
+ function createValidationSettingsMock(target) {
184
+ return {
185
+ ...createMockStandardRenderingApi(target),
186
+ applyMetafieldChange: async () => index.createResult('applyMetafieldChange'),
187
+ data: {
188
+ validation: undefined,
189
+ shopifyFunction: {
190
+ id: 'gid://shopify/ShopifyFunction/1'
191
+ }
192
+ }
193
+ };
194
+ }
195
+ function createPurchaseOptionsCardMock(target) {
196
+ return {
197
+ ...createMockActionApi(target),
198
+ data: {
199
+ selected: []
200
+ }
201
+ };
202
+ }
203
+ function createCustomerSegmentTemplateMock(target) {
204
+ return {
205
+ ...createMockStandardApi(target)
206
+ };
207
+ }
208
+
209
+ // ---------------------------------------------------------------------------
210
+ // Factory map — TypeScript verifies each entry against ApiForTarget<K>
211
+ // ---------------------------------------------------------------------------
212
+
213
+ const adminMockFactories = {
214
+ // Runnable targets
215
+ 'admin.customers.segmentation-templates.data': createCustomerSegmentTemplateMock,
216
+ 'admin.app.tools.data': createMockStandardApi,
217
+ // Block targets
218
+ 'admin.product-details.block.render': createMockBlockApi,
219
+ 'admin.order-details.block.render': createMockBlockApi,
220
+ 'admin.customer-details.block.render': createMockBlockApi,
221
+ 'admin.collection-details.block.render': createMockBlockApi,
222
+ 'admin.draft-order-details.block.render': createMockBlockApi,
223
+ 'admin.abandoned-checkout-details.block.render': createMockBlockApi,
224
+ 'admin.catalog-details.block.render': createMockBlockApi,
225
+ 'admin.company-details.block.render': createMockBlockApi,
226
+ 'admin.company-location-details.block.render': createMockBlockApi,
227
+ 'admin.gift-card-details.block.render': createMockBlockApi,
228
+ 'admin.product-variant-details.block.render': createMockBlockApi,
229
+ 'admin.product-details.reorder.render': createMockBlockApi,
230
+ // Action targets
231
+ 'admin.product-details.action.render': createMockActionApi,
232
+ 'admin.catalog-details.action.render': createMockActionApi,
233
+ 'admin.company-details.action.render': createMockActionApi,
234
+ 'admin.gift-card-details.action.render': createMockActionApi,
235
+ 'admin.order-details.action.render': createMockActionApi,
236
+ 'admin.customer-details.action.render': createMockActionApi,
237
+ 'admin.customer-segment-details.action.render': createMockActionApi,
238
+ 'admin.product-index.action.render': createMockActionApi,
239
+ 'admin.order-index.action.render': createMockActionApi,
240
+ 'admin.customer-index.action.render': createMockActionApi,
241
+ 'admin.discount-index.action.render': createMockActionApi,
242
+ 'admin.collection-details.action.render': createMockActionApi,
243
+ 'admin.collection-index.action.render': createMockActionApi,
244
+ 'admin.abandoned-checkout-details.action.render': createMockActionApi,
245
+ 'admin.product-variant-details.action.render': createMockActionApi,
246
+ 'admin.draft-order-details.action.render': createMockActionApi,
247
+ 'admin.draft-order-index.action.render': createMockActionApi,
248
+ 'admin.discount-details.action.render': createMockActionApi,
249
+ 'admin.order-fulfilled-card.action.render': createMockActionApi,
250
+ // Bulk action targets
251
+ 'admin.product-index.selection-action.render': createMockActionApi,
252
+ 'admin.order-index.selection-action.render': createMockActionApi,
253
+ 'admin.customer-index.selection-action.render': createMockActionApi,
254
+ 'admin.draft-order-index.selection-action.render': createMockActionApi,
255
+ 'admin.discount-index.selection-action.render': createMockActionApi,
256
+ // Purchase options card action targets
257
+ 'admin.product-purchase-option.action.render': createPurchaseOptionsCardMock,
258
+ 'admin.product-variant-purchase-option.action.render': createPurchaseOptionsCardMock,
259
+ // Print action targets
260
+ 'admin.order-details.print-action.render': createPrintActionMock,
261
+ 'admin.product-details.print-action.render': createPrintActionMock,
262
+ 'admin.order-index.selection-print-action.render': createPrintActionMock,
263
+ 'admin.product-index.selection-print-action.render': createPrintActionMock,
264
+ // Configuration targets
265
+ 'admin.product-details.configuration.render': createProductDetailsConfigMock,
266
+ 'admin.product-variant-details.configuration.render': createProductVariantDetailsConfigMock,
267
+ // Function settings targets
268
+ 'admin.discount-details.function-settings.render': createDiscountFunctionSettingsMock,
269
+ 'admin.settings.internal-order-routing-rule.render': createOrderRoutingRuleMock,
270
+ 'admin.settings.order-routing-rule.render': createOrderRoutingRuleMock,
271
+ 'admin.settings.validation.render': createValidationSettingsMock,
272
+ // Should-render targets (action)
273
+ 'admin.product-details.action.should-render': createShouldRenderMock,
274
+ 'admin.catalog-details.action.should-render': createShouldRenderMock,
275
+ 'admin.company-details.action.should-render': createShouldRenderMock,
276
+ 'admin.gift-card-details.action.should-render': createShouldRenderMock,
277
+ 'admin.order-details.action.should-render': createShouldRenderMock,
278
+ 'admin.customer-details.action.should-render': createShouldRenderMock,
279
+ 'admin.customer-segment-details.action.should-render': createShouldRenderMock,
280
+ 'admin.product-index.action.should-render': createShouldRenderMock,
281
+ 'admin.order-index.action.should-render': createShouldRenderMock,
282
+ 'admin.customer-index.action.should-render': createShouldRenderMock,
283
+ 'admin.discount-index.action.should-render': createShouldRenderMock,
284
+ 'admin.collection-details.action.should-render': createShouldRenderMock,
285
+ 'admin.collection-index.action.should-render': createShouldRenderMock,
286
+ 'admin.abandoned-checkout-details.action.should-render': createShouldRenderMock,
287
+ 'admin.product-variant-details.action.should-render': createShouldRenderMock,
288
+ 'admin.draft-order-details.action.should-render': createShouldRenderMock,
289
+ 'admin.draft-order-index.action.should-render': createShouldRenderMock,
290
+ 'admin.discount-details.action.should-render': createShouldRenderMock,
291
+ 'admin.order-fulfilled-card.action.should-render': createShouldRenderMock,
292
+ // Should-render targets (bulk action)
293
+ 'admin.product-index.selection-action.should-render': createShouldRenderMock,
294
+ 'admin.order-index.selection-action.should-render': createShouldRenderMock,
295
+ 'admin.customer-index.selection-action.should-render': createShouldRenderMock,
296
+ 'admin.draft-order-index.selection-action.should-render': createShouldRenderMock,
297
+ 'admin.discount-index.selection-action.should-render': createShouldRenderMock,
298
+ // Should-render targets (print action)
299
+ 'admin.order-details.print-action.should-render': createShouldRenderMock,
300
+ 'admin.product-details.print-action.should-render': createShouldRenderMock,
301
+ 'admin.order-index.selection-print-action.should-render': createShouldRenderMock,
302
+ 'admin.product-index.selection-print-action.should-render': createShouldRenderMock
303
+ };
304
+
305
+ // ---------------------------------------------------------------------------
306
+ // Main factory
307
+ // ---------------------------------------------------------------------------
308
+
309
+ /**
310
+ * Creates a complete mock API for an admin extension target.
311
+ * Each entry in the factory map is type-checked by TypeScript against
312
+ * the concrete API type for that target.
313
+ */
314
+ function createMockAdminTargetApi(target) {
315
+ const factory = adminMockFactories[target];
316
+ if (!factory) {
317
+ throw new Error(`Unsupported admin target: "${target}". ` + 'Add an entry for this target in adminMockFactories.');
318
+ }
319
+ return factory(target);
320
+ }
321
+
322
+ exports.createMockAdminTargetApi = createMockAdminTargetApi;
323
+ exports.gidFromTarget = gidFromTarget;
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * Creates a mock `Storage` instance.
7
+ *
8
+ * Optionally accepts a `Record<string, unknown>` of initial entries.
9
+ */
10
+ function createStorage(initialEntries) {
11
+ const store = new Map(initialEntries ? Object.entries(initialEntries) : []);
12
+ return {
13
+ set: async (key, value) => {
14
+ store.set(key, value);
15
+ },
16
+ setMany: async entries => {
17
+ for (const [entryKey, entryValue] of Object.entries(entries)) {
18
+ store.set(entryKey, entryValue);
19
+ }
20
+ },
21
+ get: async key => store.get(key),
22
+ getMany: async keys => keys.map(entry => store.get(entry)),
23
+ clear: async () => {
24
+ store.clear();
25
+ },
26
+ delete: async key => store.delete(key),
27
+ deleteMany: async keys => {
28
+ const result = {};
29
+ for (const entry of keys) {
30
+ result[entry] = store.delete(entry);
31
+ }
32
+ return result;
33
+ },
34
+ entries: async () => store.entries()
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Maps each admin mutation API name to its result type.
40
+ */
41
+
42
+ const adminMutationDefaults = {
43
+ applyMetafieldChange: () => ({
44
+ type: 'success'
45
+ }),
46
+ updateDiscountClasses: () => ({
47
+ success: true,
48
+ value: []
49
+ })
50
+ };
51
+
52
+ /**
53
+ * Creates a typed mock result for an admin mutation API.
54
+ *
55
+ * @param mutation - The mutation API name (e.g. `'applyMetafieldChange'`).
56
+ * @param result - Optional partial override merged with the default.
57
+ *
58
+ * @example
59
+ * createResult('applyMetafieldChange');
60
+ * createResult('updateDiscountClasses', {value: ['ORDER']});
61
+ */
62
+ function createResult(mutation, result) {
63
+ return {
64
+ ...adminMutationDefaults[mutation](),
65
+ ...result
66
+ };
67
+ }
68
+
69
+ exports.createResult = createResult;
70
+ exports.createStorage = createStorage;
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * The API version supported by this version of the library.
7
+ *
8
+ * At build time, `"2026.4.0-rc.3"` is replaced by rollup with the
9
+ * raw NPM version string from package.json (e.g. `"2026.4.0-rc.1"`).
10
+ *
11
+ * When running from source (e.g. in tests), the placeholder is still
12
+ * present, so we fall back to reading package.json via require.
13
+ */
14
+
15
+ const npmVersion = "2026.4.0-rc.3";
16
+ function npmVersionToApiVersion(version) {
17
+ const [year, minor] = version.split('.');
18
+ return `${year}-${minor.padStart(2, '0')}`;
19
+ }
20
+ const API_VERSION = npmVersionToApiVersion(npmVersion);
21
+
22
+ exports.API_VERSION = API_VERSION;