@drip-apex/sdk 0.1.0 → 0.3.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.
- package/README.md +5 -0
- package/dist/bundle-report.json +584 -226
- package/dist/define.cjs +123 -0
- package/dist/define.cjs.map +7 -0
- package/dist/define.mjs +102 -0
- package/dist/define.mjs.map +7 -0
- package/dist/drip.cjs +19283 -0
- package/dist/drip.cjs.map +7 -0
- package/dist/drip.debug.js +1 -1
- package/dist/drip.debug.js.map +1 -1
- package/dist/drip.heatmap.js +1 -1
- package/dist/drip.heatmap.js.map +1 -1
- package/dist/drip.js +1 -1
- package/dist/drip.js.map +1 -1
- package/dist/drip.live.js +1 -1
- package/dist/drip.live.js.map +1 -1
- package/dist/drip.mjs +19267 -0
- package/dist/drip.mjs.map +7 -0
- package/dist/drip.replay-recorder.js +2 -0
- package/dist/drip.replay-recorder.js.map +1 -0
- package/dist/editor.js +147 -142
- package/dist/editor.js.map +4 -4
- package/dist/flags.cjs +1788 -0
- package/dist/flags.cjs.map +7 -0
- package/dist/flags.mjs +1765 -0
- package/dist/flags.mjs.map +7 -0
- package/dist/index.mjs +12 -0
- package/dist/index.mjs.map +2 -2
- package/dist/metafiles/define.cjs.meta.json +28 -0
- package/dist/metafiles/define.mjs.meta.json +32 -0
- package/dist/metafiles/drip.cjs.meta.json +3193 -0
- package/dist/metafiles/drip.debug.meta.json +2859 -574
- package/dist/metafiles/drip.heatmap.meta.json +2732 -460
- package/dist/metafiles/drip.live.meta.json +2732 -460
- package/dist/metafiles/drip.meta.json +2859 -574
- package/dist/metafiles/drip.mjs.meta.json +3235 -0
- package/dist/metafiles/drip.replay-recorder.meta.json +82 -0
- package/dist/metafiles/editor.meta.json +67 -27
- package/dist/metafiles/flags.cjs.meta.json +220 -0
- package/dist/metafiles/flags.mjs.meta.json +225 -0
- package/dist/metafiles/index.meta.json +2717 -491
- package/dist/metafiles/index.mjs.meta.json +14 -4
- package/dist/react/index.js +16636 -13533
- package/dist/react/index.js.map +4 -4
- package/dist/sri.json +20 -15
- package/dist/types/activation-runtime.d.ts +91 -0
- package/dist/types/analytics-runtime.d.ts +166 -0
- package/dist/types/antiflicker.d.ts +9 -3
- package/dist/types/assignment-cookie-sync.d.ts +31 -0
- package/dist/types/assignment-runtime.d.ts +257 -0
- package/dist/types/assignment-store.d.ts +4 -8
- package/dist/types/bucket.d.ts +1 -2
- package/dist/types/compact-store.d.ts +1 -0
- package/dist/types/config-runtime.d.ts +313 -0
- package/dist/types/consent-evaluation.d.ts +28 -0
- package/dist/types/css.d.ts +5 -3
- package/dist/types/debug-loader.d.ts +2 -0
- package/dist/types/decide-assignments.d.ts +31 -0
- package/dist/types/delivery-timing.d.ts +8 -0
- package/dist/types/early-interaction-capture.d.ts +79 -0
- package/dist/types/early-reassert.d.ts +32 -0
- package/dist/types/edge-runtime.d.ts +11 -0
- package/dist/types/editor/api.d.ts +3 -0
- package/dist/types/editor/controller.d.ts +3 -1
- package/dist/types/editor/publication-result.d.ts +11 -0
- package/dist/types/editor/types.d.ts +2 -1
- package/dist/types/editor/view-kit.d.ts +1 -1
- package/dist/types/endpoint.d.ts +8 -0
- package/dist/types/exclusion-groups.d.ts +4 -7
- package/dist/types/flags.d.ts +2 -0
- package/dist/types/goal-eligibility.d.ts +4 -0
- package/dist/types/goals.d.ts +10 -1
- package/dist/types/guards.d.ts +7 -7
- package/dist/types/handover.d.ts +12 -1
- package/dist/types/hash.d.ts +8 -4
- package/dist/types/hydration.d.ts +2 -1
- package/dist/types/index.d.ts +24 -128
- package/dist/types/init-test-helpers.d.ts +48 -0
- package/dist/types/inline-bootstrap.d.ts +26 -0
- package/dist/types/js.d.ts +3 -1
- package/dist/types/money.d.ts +12 -0
- package/dist/types/mutate.d.ts +45 -6
- package/dist/types/performance.d.ts +2 -0
- package/dist/types/persistence-decoders.d.ts +12 -0
- package/dist/types/public-api.d.ts +209 -0
- package/dist/types/qa-assistant-state.d.ts +34 -0
- package/dist/types/react/index.d.ts +28 -3
- package/dist/types/reassert-sentinel.d.ts +6 -0
- package/dist/types/redirect.d.ts +48 -0
- package/dist/types/replay-recorder-entry.d.ts +1 -0
- package/dist/types/replay-signal-state.d.ts +6 -0
- package/dist/types/replay-signals.d.ts +13 -0
- package/dist/types/replay.d.ts +110 -0
- package/dist/types/router.d.ts +12 -2
- package/dist/types/runtime-state.d.ts +166 -0
- package/dist/types/sanitize.d.ts +1 -0
- package/dist/types/shadow.d.ts +3 -0
- package/dist/types/shopify-cart.d.ts +25 -1
- package/dist/types/storefront-vitals.d.ts +24 -0
- package/dist/types/targeting-diagnostics.d.ts +1 -0
- package/dist/types/targeting.d.ts +16 -2
- package/dist/types/track.d.ts +15 -1
- package/dist/types/types.d.ts +115 -9
- package/dist/types/wait.d.ts +14 -1
- package/dist/types/weekday-schedule.d.ts +3 -0
- package/package.json +17 -8
- package/src/activation-runtime.ts +2737 -0
- package/src/analytics-runtime.ts +2175 -0
- package/src/antiflicker.test.ts +216 -44
- package/src/antiflicker.ts +103 -28
- package/src/artifact-concurrency.test.ts +1091 -0
- package/src/assignment-cookie-sync.test.ts +202 -0
- package/src/assignment-cookie-sync.ts +189 -0
- package/src/assignment-runtime.ts +3204 -0
- package/src/assignment-store.test.ts +56 -0
- package/src/assignment-store.ts +7 -38
- package/src/bucket.ts +3 -18
- package/src/commerce-analytics-lifecycle.test.ts +75 -15
- package/src/commerce-config-lifecycle.test.ts +81 -1
- package/src/commerce-price-preserve.test.ts +133 -0
- package/src/commerce-price.test.ts +97 -0
- package/src/commerce-price.ts +74 -20
- package/src/commerce-shipping.test.ts +53 -0
- package/src/commerce-shipping.ts +5 -11
- package/src/compact-store.ts +15 -0
- package/src/config-fetch.test.ts +480 -9
- package/src/config-runtime.ts +2071 -0
- package/src/consent-evaluation-borlabs.test.ts +41 -0
- package/src/consent-evaluation-cookiescript.test.ts +50 -0
- package/src/consent-evaluation.ts +151 -0
- package/src/css.test.ts +30 -0
- package/src/css.ts +120 -6
- package/src/cwv.test.ts +60 -77
- package/src/debug-loader.test.ts +214 -0
- package/src/debug-loader.ts +41 -0
- package/src/decide-assignments.test.ts +196 -0
- package/src/decide-assignments.ts +204 -0
- package/src/delivery-timing.test.ts +104 -0
- package/src/delivery-timing.ts +89 -0
- package/src/early-interaction-capture.test.ts +451 -0
- package/src/early-interaction-capture.ts +230 -0
- package/src/early-reassert.test.ts +207 -0
- package/src/early-reassert.ts +152 -0
- package/src/edge-adoption.test.ts +435 -0
- package/src/edge-runtime.ts +30 -0
- package/src/editor/api.test.ts +109 -0
- package/src/editor/api.ts +34 -3
- package/src/editor/controller.test.ts +297 -14
- package/src/editor/controller.ts +69 -5
- package/src/editor/index.test.ts +2 -0
- package/src/editor/index.ts +1 -0
- package/src/editor/publication-result.ts +58 -0
- package/src/editor/types.ts +10 -1
- package/src/editor/view-kit.ts +2 -1
- package/src/editor/view.test.ts +108 -0
- package/src/editor/view.ts +49 -7
- package/src/endpoint.test.ts +15 -0
- package/src/endpoint.ts +10 -0
- package/src/exclusion-groups.ts +8 -18
- package/src/flags.test.ts +88 -1
- package/src/flags.ts +29 -29
- package/src/global-runtime-reconciler.test.ts +271 -0
- package/src/goal-eligibility.test.ts +29 -0
- package/src/goal-eligibility.ts +17 -0
- package/src/goals.test.ts +144 -1
- package/src/goals.ts +97 -18
- package/src/guards.test.ts +99 -1
- package/src/guards.ts +34 -15
- package/src/handover-cache-order.test.ts +6 -3
- package/src/handover.test.ts +154 -8
- package/src/handover.ts +122 -12
- package/src/hash.ts +29 -54
- package/src/holdout.test.ts +26 -0
- package/src/hydration.test.ts +73 -2
- package/src/hydration.ts +18 -9
- package/src/index.ts +130 -7287
- package/src/init-analytics.test.ts +1694 -0
- package/src/init-anti-flicker.test.ts +1211 -0
- package/src/init-cart-attributes.test.ts +2003 -0
- package/src/init-config-resolution.test.ts +999 -0
- package/src/init-consent.test.ts +971 -0
- package/src/init-empty.test.ts +11 -5406
- package/src/init-integrations.test.ts +846 -0
- package/src/init-page-activation.test.ts +5064 -0
- package/src/init-qa-loading.test.ts +740 -0
- package/src/init-redirects.test.ts +2156 -0
- package/src/init-test-helpers.ts +287 -0
- package/src/inline-bootstrap.test.ts +184 -0
- package/src/inline-bootstrap.ts +73 -0
- package/src/js.test.ts +51 -1
- package/src/js.ts +86 -2
- package/src/money.test.ts +55 -1
- package/src/money.ts +104 -2
- package/src/money.web-parity.contract.test.ts +85 -0
- package/src/mutate.test.ts +474 -10
- package/src/mutate.ts +739 -230
- package/src/page-trigger.test.ts +218 -8
- package/src/performance.ts +10 -0
- package/src/persistence-decoders.ts +18 -0
- package/src/public-api.ts +1828 -0
- package/src/qa-assistant-state.test.ts +249 -3
- package/src/qa-assistant-state.ts +146 -6
- package/src/qa-assistant-view.test.ts +220 -2
- package/src/qa-assistant-view.ts +102 -5
- package/src/react/index.test.tsx +37 -0
- package/src/react/index.tsx +19 -3
- package/src/reassert-sentinel.test.ts +155 -1
- package/src/reassert-sentinel.ts +168 -8
- package/src/redirect.test.ts +541 -0
- package/src/redirect.ts +572 -0
- package/src/replay-recorder-entry.ts +115 -0
- package/src/replay-signal-state.ts +100 -0
- package/src/replay-signals.test.ts +249 -0
- package/src/replay-signals.ts +151 -0
- package/src/replay.test.ts +764 -0
- package/src/replay.ts +514 -0
- package/src/router.test.ts +61 -2
- package/src/router.ts +50 -12
- package/src/runtime-state.ts +507 -0
- package/src/runtime.test.ts +174 -7
- package/src/runtime.ts +88 -14
- package/src/sanitize.test.ts +34 -0
- package/src/sanitize.ts +23 -12
- package/src/shadow.test.ts +187 -0
- package/src/shadow.ts +99 -0
- package/src/shopify-cart.test.ts +733 -23
- package/src/shopify-cart.ts +402 -49
- package/src/storefront-vitals.test.ts +217 -0
- package/src/storefront-vitals.ts +206 -0
- package/src/surface-signals.ts +6 -0
- package/src/targeting-conformance.test.ts +9 -0
- package/src/targeting-diagnostics.ts +38 -8
- package/src/targeting-parity-corpus.json +559 -0
- package/src/targeting-parity-corpus.test.ts +18 -0
- package/src/targeting.detailed.test.ts +105 -0
- package/src/targeting.test.ts +211 -0
- package/src/targeting.ts +88 -207
- package/src/track.test.ts +147 -0
- package/src/track.ts +125 -26
- package/src/types.ts +120 -13
- package/src/wait.test.ts +23 -0
- package/src/wait.ts +129 -13
- package/src/weekday-delivery.test.ts +56 -0
- package/src/weekday-schedule-parity-corpus.json +92 -0
- package/src/weekday-schedule.test.ts +69 -0
- package/src/weekday-schedule.ts +20 -0
package/src/page-trigger.test.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import { __test } from "./index";
|
|
3
3
|
import { clearRuntimeSignal, getSignals } from "./signals";
|
|
4
|
-
import type { PageTargetingRule } from "./types";
|
|
4
|
+
import type { PageTargetingRule, SegmentCondition } from "./types";
|
|
5
5
|
|
|
6
6
|
const signal = "page.trigger.pdp_overlay";
|
|
7
|
+
const segmentSignal = "custom.callback.ready";
|
|
7
8
|
|
|
8
|
-
function installTrigger(
|
|
9
|
+
function installTrigger(
|
|
10
|
+
triggerJs: string,
|
|
11
|
+
mode: "manual-callback" | "manual-api" = "manual-callback",
|
|
12
|
+
) {
|
|
9
13
|
const onChange = vi.fn();
|
|
10
14
|
const cleanup = __test.installPageTriggerRule({
|
|
11
15
|
id: "page_1",
|
|
12
16
|
includeRules: [{ type: "simple", pattern: "/products/*", include: true }],
|
|
13
17
|
trigger: {
|
|
14
|
-
mode
|
|
18
|
+
mode,
|
|
15
19
|
apiName: "pdp_overlay",
|
|
16
20
|
signal,
|
|
17
21
|
triggerJs,
|
|
@@ -20,26 +24,232 @@ function installTrigger(triggerJs: string) {
|
|
|
20
24
|
return { cleanup, onChange };
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
function installSegmentTrigger(triggerJs: string) {
|
|
28
|
+
const onChange = vi.fn();
|
|
29
|
+
const cleanup = __test.installActivateJsTrigger({
|
|
30
|
+
signal: segmentSignal,
|
|
31
|
+
operator: "equals",
|
|
32
|
+
value: true,
|
|
33
|
+
js: {
|
|
34
|
+
mode: "activate",
|
|
35
|
+
code: triggerJs,
|
|
36
|
+
},
|
|
37
|
+
} satisfies SegmentCondition, onChange);
|
|
38
|
+
return { cleanup, onChange };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function installRerunEnvironment() {
|
|
42
|
+
class FakeElement {
|
|
43
|
+
getAttribute() { return ""; }
|
|
44
|
+
closest() { return null; }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let mutationCallback: MutationCallback | null = null;
|
|
48
|
+
const disconnect = vi.fn();
|
|
49
|
+
const location = { href: "https://shop.test/products/example" };
|
|
50
|
+
vi.stubGlobal("Element", FakeElement);
|
|
51
|
+
vi.stubGlobal("location", location);
|
|
52
|
+
vi.stubGlobal("document", { documentElement: new FakeElement() });
|
|
53
|
+
vi.stubGlobal("window", {
|
|
54
|
+
clearInterval,
|
|
55
|
+
clearTimeout,
|
|
56
|
+
location,
|
|
57
|
+
setInterval,
|
|
58
|
+
setTimeout,
|
|
59
|
+
});
|
|
60
|
+
vi.stubGlobal("MutationObserver", class MutationObserver {
|
|
61
|
+
constructor(callback: MutationCallback) {
|
|
62
|
+
mutationCallback = callback;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
observe = vi.fn();
|
|
66
|
+
disconnect = disconnect;
|
|
67
|
+
takeRecords = vi.fn(() => []);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
disconnect,
|
|
72
|
+
mutate() {
|
|
73
|
+
mutationCallback?.([
|
|
74
|
+
{
|
|
75
|
+
target: (globalThis as any).document.documentElement,
|
|
76
|
+
type: "attributes",
|
|
77
|
+
} as MutationRecord,
|
|
78
|
+
], {} as MutationObserver);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
23
83
|
describe("Page trigger JS", () => {
|
|
24
84
|
afterEach(() => {
|
|
85
|
+
vi.clearAllTimers();
|
|
86
|
+
vi.useRealTimers();
|
|
25
87
|
clearRuntimeSignal(signal);
|
|
88
|
+
clearRuntimeSignal(segmentSignal);
|
|
26
89
|
clearRuntimeSignal("page.trigger.segment_123_pdp_overlay");
|
|
27
90
|
vi.unstubAllGlobals();
|
|
28
91
|
});
|
|
29
92
|
|
|
30
|
-
it("
|
|
31
|
-
|
|
93
|
+
it("re-runs an inactive manual callback after a DOM change and stops after activation", async () => {
|
|
94
|
+
vi.useFakeTimers();
|
|
95
|
+
const environment = installRerunEnvironment();
|
|
96
|
+
(globalThis as any).window.__eligible = false;
|
|
97
|
+
(globalThis as any).window.__attempts = 0;
|
|
98
|
+
const trigger = installTrigger(`
|
|
99
|
+
window.__attempts += 1;
|
|
100
|
+
if (window.__eligible) activate();
|
|
101
|
+
`);
|
|
102
|
+
|
|
103
|
+
expect((globalThis as any).window.__attempts).toBe(1);
|
|
104
|
+
expect(getSignals()[signal]).toBeUndefined();
|
|
105
|
+
|
|
106
|
+
(globalThis as any).window.__eligible = true;
|
|
107
|
+
environment.mutate();
|
|
108
|
+
await vi.advanceTimersByTimeAsync(250);
|
|
109
|
+
|
|
110
|
+
expect((globalThis as any).window.__attempts).toBe(2);
|
|
32
111
|
expect(getSignals()[signal]).toBe(true);
|
|
33
112
|
expect(trigger.onChange).toHaveBeenCalledTimes(1);
|
|
113
|
+
expect(environment.disconnect).toHaveBeenCalledTimes(1);
|
|
114
|
+
|
|
115
|
+
environment.mutate();
|
|
116
|
+
await vi.advanceTimersByTimeAsync(2_000);
|
|
117
|
+
expect((globalThis as any).window.__attempts).toBe(2);
|
|
34
118
|
trigger.cleanup();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("does not schedule re-runs when the initial callback activates", () => {
|
|
122
|
+
vi.useFakeTimers();
|
|
123
|
+
installRerunEnvironment();
|
|
124
|
+
const setIntervalSpy = vi.spyOn(globalThis, "setInterval");
|
|
125
|
+
const trigger = installTrigger("activate();");
|
|
35
126
|
|
|
36
|
-
trigger = installTrigger("activate(true);");
|
|
37
127
|
expect(getSignals()[signal]).toBe(true);
|
|
38
|
-
expect(
|
|
128
|
+
expect(setIntervalSpy).not.toHaveBeenCalled();
|
|
129
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
130
|
+
trigger.cleanup();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("stops pending re-runs when the trigger lifecycle is cleaned up", async () => {
|
|
134
|
+
vi.useFakeTimers();
|
|
135
|
+
const environment = installRerunEnvironment();
|
|
136
|
+
(globalThis as any).window.__attempts = 0;
|
|
137
|
+
const trigger = installTrigger("window.__attempts += 1;");
|
|
138
|
+
|
|
139
|
+
expect((globalThis as any).window.__attempts).toBe(1);
|
|
140
|
+
expect(vi.getTimerCount()).toBe(2);
|
|
141
|
+
trigger.cleanup();
|
|
142
|
+
|
|
143
|
+
expect(environment.disconnect).toHaveBeenCalledTimes(1);
|
|
144
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
145
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
146
|
+
expect((globalThis as any).window.__attempts).toBe(1);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("keeps legacy manual-api trigger JS one-shot", async () => {
|
|
150
|
+
vi.useFakeTimers();
|
|
151
|
+
installRerunEnvironment();
|
|
152
|
+
(globalThis as any).window.__attempts = 0;
|
|
153
|
+
const trigger = installTrigger("window.__attempts += 1;", "manual-api");
|
|
154
|
+
|
|
155
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
156
|
+
expect((globalThis as any).window.__attempts).toBe(1);
|
|
157
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
39
158
|
trigger.cleanup();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("stops a never-eligible callback after ten bounded re-runs", async () => {
|
|
162
|
+
vi.useFakeTimers();
|
|
163
|
+
const environment = installRerunEnvironment();
|
|
164
|
+
(globalThis as any).window.__attempts = 0;
|
|
165
|
+
const trigger = installTrigger("window.__attempts += 1;");
|
|
166
|
+
|
|
167
|
+
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
168
|
+
environment.mutate();
|
|
169
|
+
await vi.advanceTimersByTimeAsync(250);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
expect((globalThis as any).window.__attempts).toBe(11);
|
|
173
|
+
expect(environment.disconnect).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
175
|
+
|
|
176
|
+
environment.mutate();
|
|
177
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
178
|
+
expect((globalThis as any).window.__attempts).toBe(11);
|
|
179
|
+
trigger.cleanup();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("counts throwing callbacks toward the re-run bound without an unhandled rejection", async () => {
|
|
183
|
+
vi.useFakeTimers();
|
|
184
|
+
const environment = installRerunEnvironment();
|
|
185
|
+
(globalThis as any).window.__attempts = 0;
|
|
186
|
+
const trigger = installTrigger(`
|
|
187
|
+
window.__attempts += 1;
|
|
188
|
+
throw new Error("not ready");
|
|
189
|
+
`);
|
|
190
|
+
|
|
191
|
+
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
192
|
+
environment.mutate();
|
|
193
|
+
await vi.advanceTimersByTimeAsync(250);
|
|
194
|
+
}
|
|
40
195
|
|
|
41
|
-
|
|
196
|
+
expect((globalThis as any).window.__attempts).toBe(11);
|
|
197
|
+
expect(environment.disconnect).toHaveBeenCalledTimes(1);
|
|
198
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
199
|
+
trigger.cleanup();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("continues bounded retries when a re-run throws without activating", async () => {
|
|
203
|
+
vi.useFakeTimers();
|
|
204
|
+
const environment = installRerunEnvironment();
|
|
205
|
+
(globalThis as any).window.__attempts = 0;
|
|
206
|
+
const trigger = installTrigger(`
|
|
207
|
+
window.__attempts += 1;
|
|
208
|
+
if (window.__attempts > 1) throw new Error("still not ready");
|
|
209
|
+
`);
|
|
210
|
+
|
|
211
|
+
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
212
|
+
environment.mutate();
|
|
213
|
+
await vi.advanceTimersByTimeAsync(250);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
expect((globalThis as any).window.__attempts).toBe(11);
|
|
42
217
|
expect(getSignals()[signal]).toBe(false);
|
|
218
|
+
expect(environment.disconnect).toHaveBeenCalledTimes(1);
|
|
219
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
220
|
+
trigger.cleanup();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it.each([
|
|
224
|
+
["no argument", "activate();", true],
|
|
225
|
+
["true", "activate(true);", true],
|
|
226
|
+
["one", "activate(1);", true],
|
|
227
|
+
["non-empty string", 'activate("yes");', true],
|
|
228
|
+
["false", "activate(false);", false],
|
|
229
|
+
["zero", "activate(0);", false],
|
|
230
|
+
["empty string", 'activate("");', false],
|
|
231
|
+
["null", "activate(null);", false],
|
|
232
|
+
["explicit undefined", "activate(undefined);", false],
|
|
233
|
+
])("treats %s with documented truthy callback semantics", (_label, code, expected) => {
|
|
234
|
+
const trigger = installTrigger(code);
|
|
235
|
+
expect(getSignals()[signal]).toBe(expected);
|
|
236
|
+
expect(trigger.onChange).toHaveBeenCalledTimes(1);
|
|
237
|
+
trigger.cleanup();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it.each([
|
|
241
|
+
["no argument", "activate();", true],
|
|
242
|
+
["true", "activate(true);", true],
|
|
243
|
+
["one", "activate(1);", true],
|
|
244
|
+
["non-empty string", 'activate("yes");', true],
|
|
245
|
+
["false", "activate(false);", false],
|
|
246
|
+
["zero", "activate(0);", false],
|
|
247
|
+
["empty string", 'activate("");', false],
|
|
248
|
+
["null", "activate(null);", false],
|
|
249
|
+
["explicit undefined", "activate(undefined);", false],
|
|
250
|
+
])("uses the same %s semantics for segment callbacks", (_label, code, expected) => {
|
|
251
|
+
const trigger = installSegmentTrigger(code);
|
|
252
|
+
expect(getSignals()[segmentSignal]).toBe(expected);
|
|
43
253
|
expect(trigger.onChange).toHaveBeenCalledTimes(1);
|
|
44
254
|
trigger.cleanup();
|
|
45
255
|
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function roundPerformance(value: number, precision = 1): number {
|
|
2
|
+
const factor = 10 ** precision;
|
|
3
|
+
return Math.round(value * factor) / factor;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function navigationEntry(): PerformanceNavigationTiming | undefined {
|
|
7
|
+
return performance.getEntriesByType?.("navigation")?.[0] as
|
|
8
|
+
| PerformanceNavigationTiming
|
|
9
|
+
| undefined;
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { decodeCompactStore } from "./compact-store";
|
|
2
|
+
|
|
3
|
+
export type PersistedAssignmentRecord = { variationId: string; epoch: number; assignedAt: number };
|
|
4
|
+
export type PersistedGroupSelection = { experimentId: string; epoch: number };
|
|
5
|
+
export type CompactGroupSelections = Record<string, [string, number]>;
|
|
6
|
+
|
|
7
|
+
export function decodePersistedAssignments(local: string | null, cookie: string | null): Record<string, PersistedAssignmentRecord> {
|
|
8
|
+
const compact = { ...decodeCompactStore(cookie, 3), ...decodeCompactStore(local, 3) };
|
|
9
|
+
const out: Record<string, PersistedAssignmentRecord> = {};
|
|
10
|
+
for (const [id, value] of Object.entries(compact)) out[id] = {
|
|
11
|
+
variationId: value[0] as string, epoch: value[1] as number, assignedAt: value[2] as number,
|
|
12
|
+
};
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function decodePersistedGroupSelections(local: string | null, cookie: string | null): CompactGroupSelections {
|
|
17
|
+
return { ...decodeCompactStore(local, 2), ...decodeCompactStore(cookie, 2) } as CompactGroupSelections;
|
|
18
|
+
}
|