@shopify/ui-extensions-tester 2026.7.0-rc.2 → 2026.7.0-rc.4
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/README.md +2 -0
- package/build/cjs/admin/factories.js +23 -0
- package/build/cjs/api-version.js +2 -2
- package/build/cjs/index.js +45 -1
- package/build/cjs/point-of-sale/factories.js +54 -0
- package/build/cjs/targets.js +8 -0
- package/build/esm/admin/factories.mjs +23 -0
- package/build/esm/api-version.mjs +2 -2
- package/build/esm/index.mjs +45 -1
- package/build/esm/point-of-sale/factories.mjs +54 -0
- package/build/esm/targets.mjs +8 -0
- package/build/esnext/admin/factories.esnext +23 -0
- package/build/esnext/api-version.esnext +2 -2
- package/build/esnext/index.esnext +45 -1
- package/build/esnext/point-of-sale/factories.esnext +54 -0
- package/build/esnext/targets.esnext +8 -0
- package/build/ts/admin/factories.d.ts.map +1 -1
- package/build/ts/index.d.ts +26 -1
- package/build/ts/index.d.ts.map +1 -1
- package/build/ts/point-of-sale/factories.d.ts.map +1 -1
- package/build/ts/targets.d.ts +9 -1
- package/build/ts/targets.d.ts.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/admin/README.md +4 -0
- package/src/admin/factories.ts +30 -0
- package/src/index.ts +75 -2
- package/src/point-of-sale/factories.ts +53 -0
- package/src/targets.ts +11 -0
- package/src/tests/admin-factories.test.ts +9 -0
- package/src/tests/shopify-events.test.ts +173 -0
package/README.md
CHANGED
|
@@ -401,6 +401,8 @@ Imports and executes the extension module's default export, rendering the extens
|
|
|
401
401
|
|
|
402
402
|
A mock `shopify` global, typed correctly for the target under test. You can mutate any property.
|
|
403
403
|
|
|
404
|
+
When testing `admin.app.home.render`, the mock `shopify` object also includes `toast`, `app`, and `loading()`.
|
|
405
|
+
|
|
404
406
|
When testing `admin.app.intent.render`, the mock `shopify.intents` object also includes `response.ok()`, `response.error()`, and `response.closed()`.
|
|
405
407
|
|
|
406
408
|
#### `extension.fetch`
|
|
@@ -77,6 +77,28 @@ function createMockStandardRenderingApi(target) {
|
|
|
77
77
|
})
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
+
function createMockToastApi() {
|
|
81
|
+
return {
|
|
82
|
+
show: () => {},
|
|
83
|
+
hide: () => {}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function createMockAppApi() {
|
|
87
|
+
return {
|
|
88
|
+
extensions: async () => []
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function createMockLoadingApi() {
|
|
92
|
+
return () => {};
|
|
93
|
+
}
|
|
94
|
+
function createAppHomeMock(target) {
|
|
95
|
+
return {
|
|
96
|
+
...createMockStandardRenderingApi(target),
|
|
97
|
+
toast: createMockToastApi(),
|
|
98
|
+
app: createMockAppApi(),
|
|
99
|
+
loading: createMockLoadingApi()
|
|
100
|
+
};
|
|
101
|
+
}
|
|
80
102
|
function createAppIntentRenderMock(target) {
|
|
81
103
|
return {
|
|
82
104
|
...createMockStandardRenderingApi(target),
|
|
@@ -231,6 +253,7 @@ const adminMockFactories = {
|
|
|
231
253
|
'admin.customers.segmentation-templates.data': createCustomerSegmentTemplateMock,
|
|
232
254
|
'admin.app.tools.data': createMockStandardApi,
|
|
233
255
|
// App render targets
|
|
256
|
+
'admin.app.home.render': createAppHomeMock,
|
|
234
257
|
'admin.app.intent.render': createAppIntentRenderMock,
|
|
235
258
|
// Block targets
|
|
236
259
|
'admin.product-details.block.render': createMockBlockApi,
|
package/build/cjs/api-version.js
CHANGED
|
@@ -5,14 +5,14 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
/**
|
|
6
6
|
* The API version supported by this version of the library.
|
|
7
7
|
*
|
|
8
|
-
* At build time, `"2026.7.0-rc.
|
|
8
|
+
* At build time, `"2026.7.0-rc.4"` is replaced by rollup with the
|
|
9
9
|
* raw NPM version string from package.json (e.g. `"2026.4.0-rc.1"`).
|
|
10
10
|
*
|
|
11
11
|
* When running from source (e.g. in tests), the placeholder is still
|
|
12
12
|
* present, so we fall back to reading package.json via require.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
const npmVersion = "2026.7.0-rc.
|
|
15
|
+
const npmVersion = "2026.7.0-rc.4";
|
|
16
16
|
function npmVersionToApiVersion(version) {
|
|
17
17
|
const [year, minor] = version.split('.');
|
|
18
18
|
return `${year}-${minor.padStart(2, '0')}`;
|
package/build/cjs/index.js
CHANGED
|
@@ -77,6 +77,9 @@ var _fetchImpl = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKe
|
|
|
77
77
|
var _previousFetch = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKey("previousFetch");
|
|
78
78
|
var _navigationImpl = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKey("navigationImpl");
|
|
79
79
|
var _previousNavigation = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKey("previousNavigation");
|
|
80
|
+
var _eventListeners = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKey("eventListeners");
|
|
81
|
+
var _addEventListener = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKey("addEventListener");
|
|
82
|
+
var _removeEventListener = /*#__PURE__*/_rollupPluginBabelHelpers.classPrivateFieldLooseKey("removeEventListener");
|
|
80
83
|
class Extension {
|
|
81
84
|
constructor(target, options) {
|
|
82
85
|
var _options$configSearch;
|
|
@@ -120,6 +123,28 @@ class Extension {
|
|
|
120
123
|
writable: true,
|
|
121
124
|
value: void 0
|
|
122
125
|
});
|
|
126
|
+
Object.defineProperty(this, _eventListeners, {
|
|
127
|
+
writable: true,
|
|
128
|
+
value: new Map()
|
|
129
|
+
});
|
|
130
|
+
Object.defineProperty(this, _addEventListener, {
|
|
131
|
+
writable: true,
|
|
132
|
+
value: (type, listener) => {
|
|
133
|
+
let set = _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type);
|
|
134
|
+
if (!set) {
|
|
135
|
+
set = new Set();
|
|
136
|
+
_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].set(type, set);
|
|
137
|
+
}
|
|
138
|
+
set.add(listener);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
Object.defineProperty(this, _removeEventListener, {
|
|
142
|
+
writable: true,
|
|
143
|
+
value: (type, listener) => {
|
|
144
|
+
var _classPrivateFieldLoo;
|
|
145
|
+
(_classPrivateFieldLoo = _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type)) === null || _classPrivateFieldLoo === void 0 ? void 0 : _classPrivateFieldLoo.delete(listener);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
123
148
|
const configSearchDir = (_options$configSearch = options === null || options === void 0 ? void 0 : options.configSearchDir) !== null && _options$configSearch !== void 0 ? _options$configSearch : path__namespace.dirname(getCallerFile());
|
|
124
149
|
const tomlPath = findToml(configSearchDir);
|
|
125
150
|
const tomlDir = path__namespace.dirname(tomlPath);
|
|
@@ -143,10 +168,28 @@ class Extension {
|
|
|
143
168
|
_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _previousFetch)[_previousFetch] = globalThis.fetch;
|
|
144
169
|
_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _previousNavigation)[_previousNavigation] = globalThis.navigation;
|
|
145
170
|
_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _navigationImpl)[_navigationImpl] = navigation.createMockNavigation();
|
|
146
|
-
|
|
171
|
+
_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].clear();
|
|
172
|
+
globalThis.shopify = deepWritableProxy(Object.assign(targetApis.createMockTargetApi(_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _target)[_target]), {
|
|
173
|
+
addEventListener: _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _addEventListener)[_addEventListener],
|
|
174
|
+
removeEventListener: _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _removeEventListener)[_removeEventListener]
|
|
175
|
+
}));
|
|
147
176
|
globalThis.fetch = _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _fetchImpl)[_fetchImpl];
|
|
148
177
|
globalThis.navigation = _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _navigationImpl)[_navigationImpl];
|
|
149
178
|
}
|
|
179
|
+
dispatch(type, event) {
|
|
180
|
+
const listeners = _rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type);
|
|
181
|
+
if (!listeners) return;
|
|
182
|
+
// Snapshot so listeners that register/unregister during dispatch
|
|
183
|
+
// don't mutate the iteration.
|
|
184
|
+
for (const listener of [...listeners]) {
|
|
185
|
+
try {
|
|
186
|
+
listener(event);
|
|
187
|
+
} catch {
|
|
188
|
+
// Fire-and-forget: per the shopify.addEventListener contract,
|
|
189
|
+
// listener errors must not affect other listeners.
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
150
193
|
get shopify() {
|
|
151
194
|
if (!globalThis.shopify) {
|
|
152
195
|
throw new Error('You must call extension.setUp() before accessing extension.shopify.');
|
|
@@ -189,6 +232,7 @@ class Extension {
|
|
|
189
232
|
document.body.innerHTML = '';
|
|
190
233
|
}
|
|
191
234
|
delete globalThis.shopify;
|
|
235
|
+
_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].clear();
|
|
192
236
|
if (_rollupPluginBabelHelpers.classPrivateFieldLooseBase(this, _previousFetch)[_previousFetch] === undefined) {
|
|
193
237
|
delete globalThis.fetch;
|
|
194
238
|
} else {
|
|
@@ -406,6 +406,58 @@ function createActionTargetCashDrawerMock(target) {
|
|
|
406
406
|
};
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
// Data target factories
|
|
410
|
+
function createDataTargetMock(target) {
|
|
411
|
+
return {
|
|
412
|
+
extensionPoint: target,
|
|
413
|
+
extension: {
|
|
414
|
+
apiVersion: '2026-04',
|
|
415
|
+
target
|
|
416
|
+
},
|
|
417
|
+
i18n: i18n.createMockI18n(),
|
|
418
|
+
session: {
|
|
419
|
+
currentSession: createSessionCurrentSession(),
|
|
420
|
+
getSessionToken: async () => 'mock-session-token',
|
|
421
|
+
deviceId: 1
|
|
422
|
+
},
|
|
423
|
+
storage: index.createStorage(),
|
|
424
|
+
locale: {
|
|
425
|
+
current: signals.createReadonlySignalLike('en-US')
|
|
426
|
+
},
|
|
427
|
+
connectivity: {
|
|
428
|
+
current: signals.createReadonlySignalLike(createConnectivityState())
|
|
429
|
+
},
|
|
430
|
+
device: {
|
|
431
|
+
name: 'Mock POS Device',
|
|
432
|
+
registerName: 'Register 1',
|
|
433
|
+
getDeviceId: async () => 'mock-device-id',
|
|
434
|
+
isTablet: async () => false
|
|
435
|
+
},
|
|
436
|
+
productSearch: {
|
|
437
|
+
searchProducts: async () => ({
|
|
438
|
+
items: [],
|
|
439
|
+
hasNextPage: false
|
|
440
|
+
}),
|
|
441
|
+
fetchProductWithId: async () => undefined,
|
|
442
|
+
fetchProductsWithIds: async () => ({
|
|
443
|
+
fetchedResources: [],
|
|
444
|
+
idsForResourcesNotFound: []
|
|
445
|
+
}),
|
|
446
|
+
fetchProductVariantWithId: async () => undefined,
|
|
447
|
+
fetchProductVariantsWithIds: async () => ({
|
|
448
|
+
fetchedResources: [],
|
|
449
|
+
idsForResourcesNotFound: []
|
|
450
|
+
}),
|
|
451
|
+
fetchProductVariantsWithProductId: async () => [],
|
|
452
|
+
fetchPaginatedProductVariantsWithProductId: async () => ({
|
|
453
|
+
items: [],
|
|
454
|
+
hasNextPage: false
|
|
455
|
+
})
|
|
456
|
+
},
|
|
457
|
+
...createMockCartApi()
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
409
461
|
// Event target factories
|
|
410
462
|
function createTransactionCompleteMock(_target) {
|
|
411
463
|
return {
|
|
@@ -491,6 +543,8 @@ const posMockFactories = {
|
|
|
491
543
|
'pos.register-details.block.render': createStandardActionCashDrawerMock,
|
|
492
544
|
// Group Q: ActionTargetApi + CashDrawerApi
|
|
493
545
|
'pos.register-details.action.render': createActionTargetCashDrawerMock,
|
|
546
|
+
// Data targets
|
|
547
|
+
'pos.app.ready.data': createDataTargetMock,
|
|
494
548
|
// Event targets
|
|
495
549
|
'pos.transaction-complete.event.observe': createTransactionCompleteMock,
|
|
496
550
|
'pos.cash-tracking-session-start.event.observe': createCashTrackingSessionStartMock,
|
package/build/cjs/targets.js
CHANGED
|
@@ -17,6 +17,14 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
17
17
|
* For event targets (functions) this is the `data` parameter type.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Maps an extension target to the event map available via
|
|
22
|
+
* `shopify.addEventListener` on that surface.
|
|
23
|
+
*
|
|
24
|
+
* - POS targets: the POS `ShopifyEventMap`.
|
|
25
|
+
* - Other surfaces: no host events, so the map is empty.
|
|
26
|
+
*/
|
|
27
|
+
|
|
20
28
|
function isCheckoutTarget(target) {
|
|
21
29
|
return target.startsWith('purchase.checkout') || target.startsWith('purchase.thank-you') || target.startsWith('purchase.cart-line-item') || target.startsWith('Checkout::');
|
|
22
30
|
}
|
|
@@ -73,6 +73,28 @@ function createMockStandardRenderingApi(target) {
|
|
|
73
73
|
})
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
+
function createMockToastApi() {
|
|
77
|
+
return {
|
|
78
|
+
show: () => {},
|
|
79
|
+
hide: () => {}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function createMockAppApi() {
|
|
83
|
+
return {
|
|
84
|
+
extensions: async () => []
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createMockLoadingApi() {
|
|
88
|
+
return () => {};
|
|
89
|
+
}
|
|
90
|
+
function createAppHomeMock(target) {
|
|
91
|
+
return {
|
|
92
|
+
...createMockStandardRenderingApi(target),
|
|
93
|
+
toast: createMockToastApi(),
|
|
94
|
+
app: createMockAppApi(),
|
|
95
|
+
loading: createMockLoadingApi()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
76
98
|
function createAppIntentRenderMock(target) {
|
|
77
99
|
return {
|
|
78
100
|
...createMockStandardRenderingApi(target),
|
|
@@ -227,6 +249,7 @@ const adminMockFactories = {
|
|
|
227
249
|
'admin.customers.segmentation-templates.data': createCustomerSegmentTemplateMock,
|
|
228
250
|
'admin.app.tools.data': createMockStandardApi,
|
|
229
251
|
// App render targets
|
|
252
|
+
'admin.app.home.render': createAppHomeMock,
|
|
230
253
|
'admin.app.intent.render': createAppIntentRenderMock,
|
|
231
254
|
// Block targets
|
|
232
255
|
'admin.product-details.block.render': createMockBlockApi,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The API version supported by this version of the library.
|
|
3
3
|
*
|
|
4
|
-
* At build time, `"2026.7.0-rc.
|
|
4
|
+
* At build time, `"2026.7.0-rc.4"` is replaced by rollup with the
|
|
5
5
|
* raw NPM version string from package.json (e.g. `"2026.4.0-rc.1"`).
|
|
6
6
|
*
|
|
7
7
|
* When running from source (e.g. in tests), the placeholder is still
|
|
8
8
|
* present, so we fall back to reading package.json via require.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const npmVersion = "2026.7.0-rc.
|
|
11
|
+
const npmVersion = "2026.7.0-rc.4";
|
|
12
12
|
function npmVersionToApiVersion(version) {
|
|
13
13
|
const [year, minor] = version.split('.');
|
|
14
14
|
return `${year}-${minor.padStart(2, '0')}`;
|
package/build/esm/index.mjs
CHANGED
|
@@ -53,6 +53,9 @@ var _fetchImpl = /*#__PURE__*/_classPrivateFieldLooseKey("fetchImpl");
|
|
|
53
53
|
var _previousFetch = /*#__PURE__*/_classPrivateFieldLooseKey("previousFetch");
|
|
54
54
|
var _navigationImpl = /*#__PURE__*/_classPrivateFieldLooseKey("navigationImpl");
|
|
55
55
|
var _previousNavigation = /*#__PURE__*/_classPrivateFieldLooseKey("previousNavigation");
|
|
56
|
+
var _eventListeners = /*#__PURE__*/_classPrivateFieldLooseKey("eventListeners");
|
|
57
|
+
var _addEventListener = /*#__PURE__*/_classPrivateFieldLooseKey("addEventListener");
|
|
58
|
+
var _removeEventListener = /*#__PURE__*/_classPrivateFieldLooseKey("removeEventListener");
|
|
56
59
|
class Extension {
|
|
57
60
|
constructor(target, options) {
|
|
58
61
|
var _options$configSearch;
|
|
@@ -96,6 +99,28 @@ class Extension {
|
|
|
96
99
|
writable: true,
|
|
97
100
|
value: void 0
|
|
98
101
|
});
|
|
102
|
+
Object.defineProperty(this, _eventListeners, {
|
|
103
|
+
writable: true,
|
|
104
|
+
value: new Map()
|
|
105
|
+
});
|
|
106
|
+
Object.defineProperty(this, _addEventListener, {
|
|
107
|
+
writable: true,
|
|
108
|
+
value: (type, listener) => {
|
|
109
|
+
let set = _classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type);
|
|
110
|
+
if (!set) {
|
|
111
|
+
set = new Set();
|
|
112
|
+
_classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].set(type, set);
|
|
113
|
+
}
|
|
114
|
+
set.add(listener);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
Object.defineProperty(this, _removeEventListener, {
|
|
118
|
+
writable: true,
|
|
119
|
+
value: (type, listener) => {
|
|
120
|
+
var _classPrivateFieldLoo;
|
|
121
|
+
(_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type)) === null || _classPrivateFieldLoo === void 0 ? void 0 : _classPrivateFieldLoo.delete(listener);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
99
124
|
const configSearchDir = (_options$configSearch = options === null || options === void 0 ? void 0 : options.configSearchDir) !== null && _options$configSearch !== void 0 ? _options$configSearch : path.dirname(getCallerFile());
|
|
100
125
|
const tomlPath = findToml(configSearchDir);
|
|
101
126
|
const tomlDir = path.dirname(tomlPath);
|
|
@@ -119,10 +144,28 @@ class Extension {
|
|
|
119
144
|
_classPrivateFieldLooseBase(this, _previousFetch)[_previousFetch] = globalThis.fetch;
|
|
120
145
|
_classPrivateFieldLooseBase(this, _previousNavigation)[_previousNavigation] = globalThis.navigation;
|
|
121
146
|
_classPrivateFieldLooseBase(this, _navigationImpl)[_navigationImpl] = createMockNavigation();
|
|
122
|
-
|
|
147
|
+
_classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].clear();
|
|
148
|
+
globalThis.shopify = deepWritableProxy(Object.assign(createMockTargetApi(_classPrivateFieldLooseBase(this, _target)[_target]), {
|
|
149
|
+
addEventListener: _classPrivateFieldLooseBase(this, _addEventListener)[_addEventListener],
|
|
150
|
+
removeEventListener: _classPrivateFieldLooseBase(this, _removeEventListener)[_removeEventListener]
|
|
151
|
+
}));
|
|
123
152
|
globalThis.fetch = _classPrivateFieldLooseBase(this, _fetchImpl)[_fetchImpl];
|
|
124
153
|
globalThis.navigation = _classPrivateFieldLooseBase(this, _navigationImpl)[_navigationImpl];
|
|
125
154
|
}
|
|
155
|
+
dispatch(type, event) {
|
|
156
|
+
const listeners = _classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type);
|
|
157
|
+
if (!listeners) return;
|
|
158
|
+
// Snapshot so listeners that register/unregister during dispatch
|
|
159
|
+
// don't mutate the iteration.
|
|
160
|
+
for (const listener of [...listeners]) {
|
|
161
|
+
try {
|
|
162
|
+
listener(event);
|
|
163
|
+
} catch {
|
|
164
|
+
// Fire-and-forget: per the shopify.addEventListener contract,
|
|
165
|
+
// listener errors must not affect other listeners.
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
126
169
|
get shopify() {
|
|
127
170
|
if (!globalThis.shopify) {
|
|
128
171
|
throw new Error('You must call extension.setUp() before accessing extension.shopify.');
|
|
@@ -165,6 +208,7 @@ class Extension {
|
|
|
165
208
|
document.body.innerHTML = '';
|
|
166
209
|
}
|
|
167
210
|
delete globalThis.shopify;
|
|
211
|
+
_classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].clear();
|
|
168
212
|
if (_classPrivateFieldLooseBase(this, _previousFetch)[_previousFetch] === undefined) {
|
|
169
213
|
delete globalThis.fetch;
|
|
170
214
|
} else {
|
|
@@ -402,6 +402,58 @@ function createActionTargetCashDrawerMock(target) {
|
|
|
402
402
|
};
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
+
// Data target factories
|
|
406
|
+
function createDataTargetMock(target) {
|
|
407
|
+
return {
|
|
408
|
+
extensionPoint: target,
|
|
409
|
+
extension: {
|
|
410
|
+
apiVersion: '2026-04',
|
|
411
|
+
target
|
|
412
|
+
},
|
|
413
|
+
i18n: createMockI18n(),
|
|
414
|
+
session: {
|
|
415
|
+
currentSession: createSessionCurrentSession(),
|
|
416
|
+
getSessionToken: async () => 'mock-session-token',
|
|
417
|
+
deviceId: 1
|
|
418
|
+
},
|
|
419
|
+
storage: createStorage(),
|
|
420
|
+
locale: {
|
|
421
|
+
current: createReadonlySignalLike('en-US')
|
|
422
|
+
},
|
|
423
|
+
connectivity: {
|
|
424
|
+
current: createReadonlySignalLike(createConnectivityState())
|
|
425
|
+
},
|
|
426
|
+
device: {
|
|
427
|
+
name: 'Mock POS Device',
|
|
428
|
+
registerName: 'Register 1',
|
|
429
|
+
getDeviceId: async () => 'mock-device-id',
|
|
430
|
+
isTablet: async () => false
|
|
431
|
+
},
|
|
432
|
+
productSearch: {
|
|
433
|
+
searchProducts: async () => ({
|
|
434
|
+
items: [],
|
|
435
|
+
hasNextPage: false
|
|
436
|
+
}),
|
|
437
|
+
fetchProductWithId: async () => undefined,
|
|
438
|
+
fetchProductsWithIds: async () => ({
|
|
439
|
+
fetchedResources: [],
|
|
440
|
+
idsForResourcesNotFound: []
|
|
441
|
+
}),
|
|
442
|
+
fetchProductVariantWithId: async () => undefined,
|
|
443
|
+
fetchProductVariantsWithIds: async () => ({
|
|
444
|
+
fetchedResources: [],
|
|
445
|
+
idsForResourcesNotFound: []
|
|
446
|
+
}),
|
|
447
|
+
fetchProductVariantsWithProductId: async () => [],
|
|
448
|
+
fetchPaginatedProductVariantsWithProductId: async () => ({
|
|
449
|
+
items: [],
|
|
450
|
+
hasNextPage: false
|
|
451
|
+
})
|
|
452
|
+
},
|
|
453
|
+
...createMockCartApi()
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
405
457
|
// Event target factories
|
|
406
458
|
function createTransactionCompleteMock(_target) {
|
|
407
459
|
return {
|
|
@@ -487,6 +539,8 @@ const posMockFactories = {
|
|
|
487
539
|
'pos.register-details.block.render': createStandardActionCashDrawerMock,
|
|
488
540
|
// Group Q: ActionTargetApi + CashDrawerApi
|
|
489
541
|
'pos.register-details.action.render': createActionTargetCashDrawerMock,
|
|
542
|
+
// Data targets
|
|
543
|
+
'pos.app.ready.data': createDataTargetMock,
|
|
490
544
|
// Event targets
|
|
491
545
|
'pos.transaction-complete.event.observe': createTransactionCompleteMock,
|
|
492
546
|
'pos.cash-tracking-session-start.event.observe': createCashTrackingSessionStartMock,
|
package/build/esm/targets.mjs
CHANGED
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
* For event targets (functions) this is the `data` parameter type.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Maps an extension target to the event map available via
|
|
18
|
+
* `shopify.addEventListener` on that surface.
|
|
19
|
+
*
|
|
20
|
+
* - POS targets: the POS `ShopifyEventMap`.
|
|
21
|
+
* - Other surfaces: no host events, so the map is empty.
|
|
22
|
+
*/
|
|
23
|
+
|
|
16
24
|
function isCheckoutTarget(target) {
|
|
17
25
|
return target.startsWith('purchase.checkout') || target.startsWith('purchase.thank-you') || target.startsWith('purchase.cart-line-item') || target.startsWith('Checkout::');
|
|
18
26
|
}
|
|
@@ -73,6 +73,28 @@ function createMockStandardRenderingApi(target) {
|
|
|
73
73
|
})
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
+
function createMockToastApi() {
|
|
77
|
+
return {
|
|
78
|
+
show: () => {},
|
|
79
|
+
hide: () => {}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function createMockAppApi() {
|
|
83
|
+
return {
|
|
84
|
+
extensions: async () => []
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createMockLoadingApi() {
|
|
88
|
+
return () => {};
|
|
89
|
+
}
|
|
90
|
+
function createAppHomeMock(target) {
|
|
91
|
+
return {
|
|
92
|
+
...createMockStandardRenderingApi(target),
|
|
93
|
+
toast: createMockToastApi(),
|
|
94
|
+
app: createMockAppApi(),
|
|
95
|
+
loading: createMockLoadingApi()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
76
98
|
function createAppIntentRenderMock(target) {
|
|
77
99
|
return {
|
|
78
100
|
...createMockStandardRenderingApi(target),
|
|
@@ -227,6 +249,7 @@ const adminMockFactories = {
|
|
|
227
249
|
'admin.customers.segmentation-templates.data': createCustomerSegmentTemplateMock,
|
|
228
250
|
'admin.app.tools.data': createMockStandardApi,
|
|
229
251
|
// App render targets
|
|
252
|
+
'admin.app.home.render': createAppHomeMock,
|
|
230
253
|
'admin.app.intent.render': createAppIntentRenderMock,
|
|
231
254
|
// Block targets
|
|
232
255
|
'admin.product-details.block.render': createMockBlockApi,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The API version supported by this version of the library.
|
|
3
3
|
*
|
|
4
|
-
* At build time, `"2026.7.0-rc.
|
|
4
|
+
* At build time, `"2026.7.0-rc.4"` is replaced by rollup with the
|
|
5
5
|
* raw NPM version string from package.json (e.g. `"2026.4.0-rc.1"`).
|
|
6
6
|
*
|
|
7
7
|
* When running from source (e.g. in tests), the placeholder is still
|
|
8
8
|
* present, so we fall back to reading package.json via require.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const npmVersion = "2026.7.0-rc.
|
|
11
|
+
const npmVersion = "2026.7.0-rc.4";
|
|
12
12
|
function npmVersionToApiVersion(version) {
|
|
13
13
|
const [year, minor] = version.split('.');
|
|
14
14
|
return `${year}-${minor.padStart(2, '0')}`;
|
|
@@ -53,6 +53,9 @@ var _fetchImpl = /*#__PURE__*/_classPrivateFieldLooseKey("fetchImpl");
|
|
|
53
53
|
var _previousFetch = /*#__PURE__*/_classPrivateFieldLooseKey("previousFetch");
|
|
54
54
|
var _navigationImpl = /*#__PURE__*/_classPrivateFieldLooseKey("navigationImpl");
|
|
55
55
|
var _previousNavigation = /*#__PURE__*/_classPrivateFieldLooseKey("previousNavigation");
|
|
56
|
+
var _eventListeners = /*#__PURE__*/_classPrivateFieldLooseKey("eventListeners");
|
|
57
|
+
var _addEventListener = /*#__PURE__*/_classPrivateFieldLooseKey("addEventListener");
|
|
58
|
+
var _removeEventListener = /*#__PURE__*/_classPrivateFieldLooseKey("removeEventListener");
|
|
56
59
|
class Extension {
|
|
57
60
|
constructor(target, options) {
|
|
58
61
|
var _options$configSearch;
|
|
@@ -96,6 +99,28 @@ class Extension {
|
|
|
96
99
|
writable: true,
|
|
97
100
|
value: void 0
|
|
98
101
|
});
|
|
102
|
+
Object.defineProperty(this, _eventListeners, {
|
|
103
|
+
writable: true,
|
|
104
|
+
value: new Map()
|
|
105
|
+
});
|
|
106
|
+
Object.defineProperty(this, _addEventListener, {
|
|
107
|
+
writable: true,
|
|
108
|
+
value: (type, listener) => {
|
|
109
|
+
let set = _classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type);
|
|
110
|
+
if (!set) {
|
|
111
|
+
set = new Set();
|
|
112
|
+
_classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].set(type, set);
|
|
113
|
+
}
|
|
114
|
+
set.add(listener);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
Object.defineProperty(this, _removeEventListener, {
|
|
118
|
+
writable: true,
|
|
119
|
+
value: (type, listener) => {
|
|
120
|
+
var _classPrivateFieldLoo;
|
|
121
|
+
(_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type)) === null || _classPrivateFieldLoo === void 0 ? void 0 : _classPrivateFieldLoo.delete(listener);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
99
124
|
const configSearchDir = (_options$configSearch = options === null || options === void 0 ? void 0 : options.configSearchDir) !== null && _options$configSearch !== void 0 ? _options$configSearch : path.dirname(getCallerFile());
|
|
100
125
|
const tomlPath = findToml(configSearchDir);
|
|
101
126
|
const tomlDir = path.dirname(tomlPath);
|
|
@@ -119,10 +144,28 @@ class Extension {
|
|
|
119
144
|
_classPrivateFieldLooseBase(this, _previousFetch)[_previousFetch] = globalThis.fetch;
|
|
120
145
|
_classPrivateFieldLooseBase(this, _previousNavigation)[_previousNavigation] = globalThis.navigation;
|
|
121
146
|
_classPrivateFieldLooseBase(this, _navigationImpl)[_navigationImpl] = createMockNavigation();
|
|
122
|
-
|
|
147
|
+
_classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].clear();
|
|
148
|
+
globalThis.shopify = deepWritableProxy(Object.assign(createMockTargetApi(_classPrivateFieldLooseBase(this, _target)[_target]), {
|
|
149
|
+
addEventListener: _classPrivateFieldLooseBase(this, _addEventListener)[_addEventListener],
|
|
150
|
+
removeEventListener: _classPrivateFieldLooseBase(this, _removeEventListener)[_removeEventListener]
|
|
151
|
+
}));
|
|
123
152
|
globalThis.fetch = _classPrivateFieldLooseBase(this, _fetchImpl)[_fetchImpl];
|
|
124
153
|
globalThis.navigation = _classPrivateFieldLooseBase(this, _navigationImpl)[_navigationImpl];
|
|
125
154
|
}
|
|
155
|
+
dispatch(type, event) {
|
|
156
|
+
const listeners = _classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].get(type);
|
|
157
|
+
if (!listeners) return;
|
|
158
|
+
// Snapshot so listeners that register/unregister during dispatch
|
|
159
|
+
// don't mutate the iteration.
|
|
160
|
+
for (const listener of [...listeners]) {
|
|
161
|
+
try {
|
|
162
|
+
listener(event);
|
|
163
|
+
} catch {
|
|
164
|
+
// Fire-and-forget: per the shopify.addEventListener contract,
|
|
165
|
+
// listener errors must not affect other listeners.
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
126
169
|
get shopify() {
|
|
127
170
|
if (!globalThis.shopify) {
|
|
128
171
|
throw new Error('You must call extension.setUp() before accessing extension.shopify.');
|
|
@@ -165,6 +208,7 @@ class Extension {
|
|
|
165
208
|
document.body.innerHTML = '';
|
|
166
209
|
}
|
|
167
210
|
delete globalThis.shopify;
|
|
211
|
+
_classPrivateFieldLooseBase(this, _eventListeners)[_eventListeners].clear();
|
|
168
212
|
if (_classPrivateFieldLooseBase(this, _previousFetch)[_previousFetch] === undefined) {
|
|
169
213
|
delete globalThis.fetch;
|
|
170
214
|
} else {
|
|
@@ -402,6 +402,58 @@ function createActionTargetCashDrawerMock(target) {
|
|
|
402
402
|
};
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
+
// Data target factories
|
|
406
|
+
function createDataTargetMock(target) {
|
|
407
|
+
return {
|
|
408
|
+
extensionPoint: target,
|
|
409
|
+
extension: {
|
|
410
|
+
apiVersion: '2026-04',
|
|
411
|
+
target
|
|
412
|
+
},
|
|
413
|
+
i18n: createMockI18n(),
|
|
414
|
+
session: {
|
|
415
|
+
currentSession: createSessionCurrentSession(),
|
|
416
|
+
getSessionToken: async () => 'mock-session-token',
|
|
417
|
+
deviceId: 1
|
|
418
|
+
},
|
|
419
|
+
storage: createStorage(),
|
|
420
|
+
locale: {
|
|
421
|
+
current: createReadonlySignalLike('en-US')
|
|
422
|
+
},
|
|
423
|
+
connectivity: {
|
|
424
|
+
current: createReadonlySignalLike(createConnectivityState())
|
|
425
|
+
},
|
|
426
|
+
device: {
|
|
427
|
+
name: 'Mock POS Device',
|
|
428
|
+
registerName: 'Register 1',
|
|
429
|
+
getDeviceId: async () => 'mock-device-id',
|
|
430
|
+
isTablet: async () => false
|
|
431
|
+
},
|
|
432
|
+
productSearch: {
|
|
433
|
+
searchProducts: async () => ({
|
|
434
|
+
items: [],
|
|
435
|
+
hasNextPage: false
|
|
436
|
+
}),
|
|
437
|
+
fetchProductWithId: async () => undefined,
|
|
438
|
+
fetchProductsWithIds: async () => ({
|
|
439
|
+
fetchedResources: [],
|
|
440
|
+
idsForResourcesNotFound: []
|
|
441
|
+
}),
|
|
442
|
+
fetchProductVariantWithId: async () => undefined,
|
|
443
|
+
fetchProductVariantsWithIds: async () => ({
|
|
444
|
+
fetchedResources: [],
|
|
445
|
+
idsForResourcesNotFound: []
|
|
446
|
+
}),
|
|
447
|
+
fetchProductVariantsWithProductId: async () => [],
|
|
448
|
+
fetchPaginatedProductVariantsWithProductId: async () => ({
|
|
449
|
+
items: [],
|
|
450
|
+
hasNextPage: false
|
|
451
|
+
})
|
|
452
|
+
},
|
|
453
|
+
...createMockCartApi()
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
405
457
|
// Event target factories
|
|
406
458
|
function createTransactionCompleteMock(_target) {
|
|
407
459
|
return {
|
|
@@ -487,6 +539,8 @@ const posMockFactories = {
|
|
|
487
539
|
'pos.register-details.block.render': createStandardActionCashDrawerMock,
|
|
488
540
|
// Group Q: ActionTargetApi + CashDrawerApi
|
|
489
541
|
'pos.register-details.action.render': createActionTargetCashDrawerMock,
|
|
542
|
+
// Data targets
|
|
543
|
+
'pos.app.ready.data': createDataTargetMock,
|
|
490
544
|
// Event targets
|
|
491
545
|
'pos.transaction-complete.event.observe': createTransactionCompleteMock,
|
|
492
546
|
'pos.cash-tracking-session-start.event.observe': createCashTrackingSessionStartMock,
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
* For event targets (functions) this is the `data` parameter type.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Maps an extension target to the event map available via
|
|
18
|
+
* `shopify.addEventListener` on that surface.
|
|
19
|
+
*
|
|
20
|
+
* - POS targets: the POS `ShopifyEventMap`.
|
|
21
|
+
* - Other surfaces: no host events, so the map is empty.
|
|
22
|
+
*/
|
|
23
|
+
|
|
16
24
|
function isCheckoutTarget(target) {
|
|
17
25
|
return target.startsWith('purchase.checkout') || target.startsWith('purchase.thank-you') || target.startsWith('purchase.cart-line-item') || target.startsWith('Checkout::');
|
|
18
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../src/admin/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,
|
|
1
|
+
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../src/admin/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EASjB,MAAM,8BAA8B,CAAC;AAKtC;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,eAAe,IACxD,gBAAgB,CAAC,CAAC,CAAC,SAAS;IAAC,GAAG,EAAE,MAAM,GAAG,CAAA;CAAC,GACxC,IAAI,CAAC,GAAG,EAAE,KAAK,MAAM,EAAE,CAAC,GACxB,KAAK,CAAC;AAsBZ,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAQ7D;AAuWD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,eAAe,EAChE,MAAM,EAAE,CAAC,GACR,oBAAoB,CAAC,CAAC,CAAC,CASzB"}
|