autotel-subscribers 52.0.0 → 54.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.
package/README.md CHANGED
@@ -151,12 +151,12 @@ const events = new Event('my-app', {
151
151
  ### Test Your Adapter
152
152
 
153
153
  ```typescript
154
- import { AdapterTestHarness } from 'autotel-subscribers/testing';
154
+ import { SubscriberTestHarness } from 'autotel-subscribers/testing';
155
155
 
156
- const harness = new AdapterTestHarness(new MySubscriber('test-key'));
156
+ const harness = new SubscriberTestHarness(new MySubscriber('test-key'));
157
157
  const results = await harness.runAll();
158
158
 
159
- AdapterTestHarness.printResults(results);
159
+ SubscriberTestHarness.printResults(results);
160
160
  // All tests passed! Your adapter is ready to use.
161
161
  ```
162
162
 
@@ -619,14 +619,14 @@ const subscriber = applyMiddleware(adapter, [
619
619
 
620
620
  ## Testing Custom Subscribers
621
621
 
622
- ### AdapterTestHarness
622
+ ### SubscriberTestHarness
623
623
 
624
624
  Validate your adapter works correctly:
625
625
 
626
626
  ```typescript
627
- import { AdapterTestHarness } from 'autotel-subscribers/testing';
627
+ import { SubscriberTestHarness } from 'autotel-subscribers/testing';
628
628
 
629
- const harness = new AdapterTestHarness(new MySubscriber());
629
+ const harness = new SubscriberTestHarness(new MySubscriber());
630
630
  const results = await harness.runAll();
631
631
 
632
632
  if (results.passed) {
@@ -636,7 +636,7 @@ if (results.passed) {
636
636
  }
637
637
 
638
638
  // Or use the built-in printer
639
- AdapterTestHarness.printResults(results);
639
+ SubscriberTestHarness.printResults(results);
640
640
  ```
641
641
 
642
642
  Tests include:
@@ -699,7 +699,7 @@ import {
699
699
 
700
700
  // Testing utilities
701
701
  import {
702
- AdapterTestHarness,
702
+ SubscriberTestHarness,
703
703
  MockWebhookServer,
704
704
  MockEventSubscriber,
705
705
  } from 'autotel-subscribers/testing';
@@ -4,150 +4,8 @@ const require_segment = require('./segment.cjs');
4
4
  const require_amplitude = require('./amplitude.cjs');
5
5
  const require_slack = require('./slack.cjs');
6
6
  const require_webhook = require('./webhook.cjs');
7
+ const require_mock_event_subscriber = require('./mock-event-subscriber-BOYF83Kq.cjs');
7
8
 
8
- //#region src/mock-event-subscriber.ts
9
- /**
10
- * Mock subscriber for testing
11
- *
12
- * Captures all events calls in memory for test assertions.
13
- * Does not make any real API calls.
14
- */
15
- var MockEventSubscriber = class {
16
- name = "MockEventSubscriber";
17
- version = "1.0.0";
18
- /**
19
- * All captured events
20
- */
21
- events = [];
22
- /**
23
- * Track if shutdown was called
24
- */
25
- shutdownCalled = false;
26
- async trackEvent(name, attributes) {
27
- this.events.push({
28
- type: "event",
29
- name,
30
- attributes,
31
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
32
- });
33
- }
34
- async trackFunnelStep(funnelName, step, attributes) {
35
- this.events.push({
36
- type: "funnel",
37
- name: `${funnelName}.${step}`,
38
- funnel: funnelName,
39
- step,
40
- attributes,
41
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
42
- });
43
- }
44
- async trackOutcome(operationName, outcome, attributes) {
45
- this.events.push({
46
- type: "outcome",
47
- name: `${operationName}.${outcome}`,
48
- operation: operationName,
49
- outcome,
50
- attributes,
51
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
52
- });
53
- }
54
- async trackValue(name, value, attributes) {
55
- this.events.push({
56
- type: "value",
57
- name,
58
- value,
59
- attributes,
60
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
61
- });
62
- }
63
- async shutdown() {
64
- this.shutdownCalled = true;
65
- }
66
- /**
67
- * Reset captured events (useful between tests)
68
- */
69
- reset() {
70
- this.events = [];
71
- this.shutdownCalled = false;
72
- }
73
- /**
74
- * Get events by type
75
- */
76
- getEventsByType(type) {
77
- return this.events.filter((e) => e.type === type);
78
- }
79
- /**
80
- * Get events by name
81
- */
82
- getEventsByName(name) {
83
- return this.events.filter((e) => e.name === name);
84
- }
85
- /**
86
- * Get funnel events for a specific funnel
87
- */
88
- getFunnelEvents(funnelName) {
89
- return this.events.filter((e) => e.type === "funnel" && e.funnel === funnelName);
90
- }
91
- /**
92
- * Get outcome events for a specific operation
93
- */
94
- getOutcomeEvents(operationName) {
95
- return this.events.filter((e) => e.type === "outcome" && e.operation === operationName);
96
- }
97
- /**
98
- * Get value events by metric name
99
- */
100
- getValueEvents(metricName) {
101
- return this.events.filter((e) => e.type === "value" && e.name === metricName);
102
- }
103
- /**
104
- * Assert that an event was tracked
105
- */
106
- assertEventTracked(name, attributes) {
107
- const events = this.getEventsByName(name);
108
- if (events.length === 0) throw new Error(`No events found with name: ${name}`);
109
- if (attributes) {
110
- if (!events.find((event) => {
111
- if (!event.attributes) return false;
112
- return Object.entries(attributes).every(([key, value]) => event.attributes[key] === value);
113
- })) throw new Error(`Event "${name}" found, but no matching attributes: ${JSON.stringify(attributes)}`);
114
- }
115
- }
116
- /**
117
- * Assert that a funnel step was tracked
118
- */
119
- assertFunnelStepTracked(funnelName, step, attributes) {
120
- const matchingEvent = this.getFunnelEvents(funnelName).find((e) => e.step === step);
121
- if (!matchingEvent) throw new Error(`Funnel "${funnelName}" step "${step}" was not tracked`);
122
- if (attributes) {
123
- if (!Object.entries(attributes).every(([key, value]) => matchingEvent.attributes?.[key] === value)) throw new Error(`Funnel step tracked, but attributes don't match: ${JSON.stringify(attributes)}`);
124
- }
125
- }
126
- /**
127
- * Assert that an outcome was tracked
128
- */
129
- assertOutcomeTracked(operationName, outcome, attributes) {
130
- const matchingEvent = this.getOutcomeEvents(operationName).find((e) => e.outcome === outcome);
131
- if (!matchingEvent) throw new Error(`Outcome "${operationName}.${outcome}" was not tracked`);
132
- if (attributes) {
133
- if (!Object.entries(attributes).every(([key, value]) => matchingEvent.attributes?.[key] === value)) throw new Error(`Outcome tracked, but attributes don't match: ${JSON.stringify(attributes)}`);
134
- }
135
- }
136
- /**
137
- * Pretty print all captured events (useful for debugging)
138
- */
139
- printEvents() {
140
- console.log(`\n[${this.name}] Captured ${this.events.length} events:\n`);
141
- for (const [index, event] of this.events.entries()) {
142
- console.log(`${index + 1}. [${event.type}] ${event.name}`);
143
- if (event.attributes) console.log(` Attributes:`, event.attributes);
144
- if (event.value !== void 0) console.log(` Value: ${event.value}`);
145
- console.log(` Timestamp: ${event.timestamp}\n`);
146
- }
147
- }
148
- };
149
-
150
- //#endregion
151
9
  //#region src/factories.ts
152
10
  /**
153
11
  * Factory functions for creating events subscribers
@@ -188,7 +46,7 @@ function createSlackSubscriber(config) {
188
46
  }
189
47
  /** Create a mock events subscriber for testing */
190
48
  function createMockSubscriber() {
191
- return new MockEventSubscriber();
49
+ return new require_mock_event_subscriber.MockEventSubscriber();
192
50
  }
193
51
  function backoffDelay(attempt, initialMs, maxMs) {
194
52
  return Math.min(maxMs, initialMs * 2 ** (attempt - 1));
@@ -1,88 +1,10 @@
1
1
  import { AmplitudeConfig } from "./amplitude.cjs";
2
+ import { t as MockEventSubscriber } from "./mock-event-subscriber-CfAyAiQn.cjs";
2
3
  import { MixpanelConfig } from "./mixpanel.cjs";
3
4
  import { SegmentConfig } from "./segment.cjs";
4
5
  import { WebhookConfig } from "./webhook.cjs";
5
6
  import { SlackSubscriberConfig } from "./slack.cjs";
6
- import { EventAttributes, EventSubscriber, FunnelStatus, OutcomeStatus } from "autotel/event-subscriber";
7
- //#region src/mock-event-subscriber.d.ts
8
- /**
9
- * Captured event data
10
- */
11
- interface CapturedEvent {
12
- type: 'event' | 'funnel' | 'outcome' | 'value';
13
- name: string;
14
- attributes?: EventAttributes;
15
- funnel?: string;
16
- step?: FunnelStatus;
17
- operation?: string;
18
- outcome?: OutcomeStatus;
19
- value?: number;
20
- timestamp: string;
21
- }
22
- /**
23
- * Mock subscriber for testing
24
- *
25
- * Captures all events calls in memory for test assertions.
26
- * Does not make any real API calls.
27
- */
28
- declare class MockEventSubscriber implements EventSubscriber {
29
- readonly name = "MockEventSubscriber";
30
- readonly version = "1.0.0";
31
- /**
32
- * All captured events
33
- */
34
- events: CapturedEvent[];
35
- /**
36
- * Track if shutdown was called
37
- */
38
- shutdownCalled: boolean;
39
- trackEvent(name: string, attributes?: EventAttributes): Promise<void>;
40
- trackFunnelStep(funnelName: string, step: FunnelStatus, attributes?: EventAttributes): Promise<void>;
41
- trackOutcome(operationName: string, outcome: OutcomeStatus, attributes?: EventAttributes): Promise<void>;
42
- trackValue(name: string, value: number, attributes?: EventAttributes): Promise<void>;
43
- shutdown(): Promise<void>;
44
- /**
45
- * Reset captured events (useful between tests)
46
- */
47
- reset(): void;
48
- /**
49
- * Get events by type
50
- */
51
- getEventsByType(type: 'event' | 'funnel' | 'outcome' | 'value'): CapturedEvent[];
52
- /**
53
- * Get events by name
54
- */
55
- getEventsByName(name: string): CapturedEvent[];
56
- /**
57
- * Get funnel events for a specific funnel
58
- */
59
- getFunnelEvents(funnelName: string): CapturedEvent[];
60
- /**
61
- * Get outcome events for a specific operation
62
- */
63
- getOutcomeEvents(operationName: string): CapturedEvent[];
64
- /**
65
- * Get value events by metric name
66
- */
67
- getValueEvents(metricName: string): CapturedEvent[];
68
- /**
69
- * Assert that an event was tracked
70
- */
71
- assertEventTracked(name: string, attributes?: Partial<EventAttributes>): void;
72
- /**
73
- * Assert that a funnel step was tracked
74
- */
75
- assertFunnelStepTracked(funnelName: string, step: FunnelStatus, attributes?: Partial<EventAttributes>): void;
76
- /**
77
- * Assert that an outcome was tracked
78
- */
79
- assertOutcomeTracked(operationName: string, outcome: OutcomeStatus, attributes?: Partial<EventAttributes>): void;
80
- /**
81
- * Pretty print all captured events (useful for debugging)
82
- */
83
- printEvents(): void;
84
- }
85
- //#endregion
7
+ import { EventSubscriber } from "autotel/event-subscriber";
86
8
  //#region src/factories.d.ts
87
9
  /** Create a Mixpanel events subscriber */
88
10
  declare function createMixpanelSubscriber(config: {
@@ -1,88 +1,10 @@
1
1
  import { AmplitudeConfig } from "./amplitude.js";
2
+ import { t as MockEventSubscriber } from "./mock-event-subscriber-CfAyAiQn.js";
2
3
  import { MixpanelConfig } from "./mixpanel.js";
3
4
  import { SegmentConfig } from "./segment.js";
4
5
  import { WebhookConfig } from "./webhook.js";
5
6
  import { SlackSubscriberConfig } from "./slack.js";
6
- import { EventAttributes, EventSubscriber, FunnelStatus, OutcomeStatus } from "autotel/event-subscriber";
7
- //#region src/mock-event-subscriber.d.ts
8
- /**
9
- * Captured event data
10
- */
11
- interface CapturedEvent {
12
- type: 'event' | 'funnel' | 'outcome' | 'value';
13
- name: string;
14
- attributes?: EventAttributes;
15
- funnel?: string;
16
- step?: FunnelStatus;
17
- operation?: string;
18
- outcome?: OutcomeStatus;
19
- value?: number;
20
- timestamp: string;
21
- }
22
- /**
23
- * Mock subscriber for testing
24
- *
25
- * Captures all events calls in memory for test assertions.
26
- * Does not make any real API calls.
27
- */
28
- declare class MockEventSubscriber implements EventSubscriber {
29
- readonly name = "MockEventSubscriber";
30
- readonly version = "1.0.0";
31
- /**
32
- * All captured events
33
- */
34
- events: CapturedEvent[];
35
- /**
36
- * Track if shutdown was called
37
- */
38
- shutdownCalled: boolean;
39
- trackEvent(name: string, attributes?: EventAttributes): Promise<void>;
40
- trackFunnelStep(funnelName: string, step: FunnelStatus, attributes?: EventAttributes): Promise<void>;
41
- trackOutcome(operationName: string, outcome: OutcomeStatus, attributes?: EventAttributes): Promise<void>;
42
- trackValue(name: string, value: number, attributes?: EventAttributes): Promise<void>;
43
- shutdown(): Promise<void>;
44
- /**
45
- * Reset captured events (useful between tests)
46
- */
47
- reset(): void;
48
- /**
49
- * Get events by type
50
- */
51
- getEventsByType(type: 'event' | 'funnel' | 'outcome' | 'value'): CapturedEvent[];
52
- /**
53
- * Get events by name
54
- */
55
- getEventsByName(name: string): CapturedEvent[];
56
- /**
57
- * Get funnel events for a specific funnel
58
- */
59
- getFunnelEvents(funnelName: string): CapturedEvent[];
60
- /**
61
- * Get outcome events for a specific operation
62
- */
63
- getOutcomeEvents(operationName: string): CapturedEvent[];
64
- /**
65
- * Get value events by metric name
66
- */
67
- getValueEvents(metricName: string): CapturedEvent[];
68
- /**
69
- * Assert that an event was tracked
70
- */
71
- assertEventTracked(name: string, attributes?: Partial<EventAttributes>): void;
72
- /**
73
- * Assert that a funnel step was tracked
74
- */
75
- assertFunnelStepTracked(funnelName: string, step: FunnelStatus, attributes?: Partial<EventAttributes>): void;
76
- /**
77
- * Assert that an outcome was tracked
78
- */
79
- assertOutcomeTracked(operationName: string, outcome: OutcomeStatus, attributes?: Partial<EventAttributes>): void;
80
- /**
81
- * Pretty print all captured events (useful for debugging)
82
- */
83
- printEvents(): void;
84
- }
85
- //#endregion
7
+ import { EventSubscriber } from "autotel/event-subscriber";
86
8
  //#region src/factories.d.ts
87
9
  /** Create a Mixpanel events subscriber */
88
10
  declare function createMixpanelSubscriber(config: {
package/dist/factories.js CHANGED
@@ -3,150 +3,8 @@ import { SegmentSubscriber } from "./segment.js";
3
3
  import { AmplitudeSubscriber } from "./amplitude.js";
4
4
  import { SlackSubscriber } from "./slack.js";
5
5
  import { WebhookSubscriber } from "./webhook.js";
6
+ import { t as MockEventSubscriber } from "./mock-event-subscriber-BKa77OVK.js";
6
7
 
7
- //#region src/mock-event-subscriber.ts
8
- /**
9
- * Mock subscriber for testing
10
- *
11
- * Captures all events calls in memory for test assertions.
12
- * Does not make any real API calls.
13
- */
14
- var MockEventSubscriber = class {
15
- name = "MockEventSubscriber";
16
- version = "1.0.0";
17
- /**
18
- * All captured events
19
- */
20
- events = [];
21
- /**
22
- * Track if shutdown was called
23
- */
24
- shutdownCalled = false;
25
- async trackEvent(name, attributes) {
26
- this.events.push({
27
- type: "event",
28
- name,
29
- attributes,
30
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
31
- });
32
- }
33
- async trackFunnelStep(funnelName, step, attributes) {
34
- this.events.push({
35
- type: "funnel",
36
- name: `${funnelName}.${step}`,
37
- funnel: funnelName,
38
- step,
39
- attributes,
40
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
41
- });
42
- }
43
- async trackOutcome(operationName, outcome, attributes) {
44
- this.events.push({
45
- type: "outcome",
46
- name: `${operationName}.${outcome}`,
47
- operation: operationName,
48
- outcome,
49
- attributes,
50
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
51
- });
52
- }
53
- async trackValue(name, value, attributes) {
54
- this.events.push({
55
- type: "value",
56
- name,
57
- value,
58
- attributes,
59
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
60
- });
61
- }
62
- async shutdown() {
63
- this.shutdownCalled = true;
64
- }
65
- /**
66
- * Reset captured events (useful between tests)
67
- */
68
- reset() {
69
- this.events = [];
70
- this.shutdownCalled = false;
71
- }
72
- /**
73
- * Get events by type
74
- */
75
- getEventsByType(type) {
76
- return this.events.filter((e) => e.type === type);
77
- }
78
- /**
79
- * Get events by name
80
- */
81
- getEventsByName(name) {
82
- return this.events.filter((e) => e.name === name);
83
- }
84
- /**
85
- * Get funnel events for a specific funnel
86
- */
87
- getFunnelEvents(funnelName) {
88
- return this.events.filter((e) => e.type === "funnel" && e.funnel === funnelName);
89
- }
90
- /**
91
- * Get outcome events for a specific operation
92
- */
93
- getOutcomeEvents(operationName) {
94
- return this.events.filter((e) => e.type === "outcome" && e.operation === operationName);
95
- }
96
- /**
97
- * Get value events by metric name
98
- */
99
- getValueEvents(metricName) {
100
- return this.events.filter((e) => e.type === "value" && e.name === metricName);
101
- }
102
- /**
103
- * Assert that an event was tracked
104
- */
105
- assertEventTracked(name, attributes) {
106
- const events = this.getEventsByName(name);
107
- if (events.length === 0) throw new Error(`No events found with name: ${name}`);
108
- if (attributes) {
109
- if (!events.find((event) => {
110
- if (!event.attributes) return false;
111
- return Object.entries(attributes).every(([key, value]) => event.attributes[key] === value);
112
- })) throw new Error(`Event "${name}" found, but no matching attributes: ${JSON.stringify(attributes)}`);
113
- }
114
- }
115
- /**
116
- * Assert that a funnel step was tracked
117
- */
118
- assertFunnelStepTracked(funnelName, step, attributes) {
119
- const matchingEvent = this.getFunnelEvents(funnelName).find((e) => e.step === step);
120
- if (!matchingEvent) throw new Error(`Funnel "${funnelName}" step "${step}" was not tracked`);
121
- if (attributes) {
122
- if (!Object.entries(attributes).every(([key, value]) => matchingEvent.attributes?.[key] === value)) throw new Error(`Funnel step tracked, but attributes don't match: ${JSON.stringify(attributes)}`);
123
- }
124
- }
125
- /**
126
- * Assert that an outcome was tracked
127
- */
128
- assertOutcomeTracked(operationName, outcome, attributes) {
129
- const matchingEvent = this.getOutcomeEvents(operationName).find((e) => e.outcome === outcome);
130
- if (!matchingEvent) throw new Error(`Outcome "${operationName}.${outcome}" was not tracked`);
131
- if (attributes) {
132
- if (!Object.entries(attributes).every(([key, value]) => matchingEvent.attributes?.[key] === value)) throw new Error(`Outcome tracked, but attributes don't match: ${JSON.stringify(attributes)}`);
133
- }
134
- }
135
- /**
136
- * Pretty print all captured events (useful for debugging)
137
- */
138
- printEvents() {
139
- console.log(`\n[${this.name}] Captured ${this.events.length} events:\n`);
140
- for (const [index, event] of this.events.entries()) {
141
- console.log(`${index + 1}. [${event.type}] ${event.name}`);
142
- if (event.attributes) console.log(` Attributes:`, event.attributes);
143
- if (event.value !== void 0) console.log(` Value: ${event.value}`);
144
- console.log(` Timestamp: ${event.timestamp}\n`);
145
- }
146
- }
147
- };
148
-
149
- //#endregion
150
8
  //#region src/factories.ts
151
9
  /**
152
10
  * Factory functions for creating events subscribers
@@ -0,0 +1,144 @@
1
+ //#region src/mock-event-subscriber.ts
2
+ /**
3
+ * Mock subscriber for testing
4
+ *
5
+ * Captures all events calls in memory for test assertions.
6
+ * Does not make any real API calls.
7
+ */
8
+ var MockEventSubscriber = class {
9
+ name = "MockEventSubscriber";
10
+ version = "1.0.0";
11
+ /**
12
+ * All captured events
13
+ */
14
+ events = [];
15
+ /**
16
+ * Track if shutdown was called
17
+ */
18
+ shutdownCalled = false;
19
+ async trackEvent(name, attributes) {
20
+ this.events.push({
21
+ type: "event",
22
+ name,
23
+ attributes,
24
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
25
+ });
26
+ }
27
+ async trackFunnelStep(funnelName, step, attributes) {
28
+ this.events.push({
29
+ type: "funnel",
30
+ name: `${funnelName}.${step}`,
31
+ funnel: funnelName,
32
+ step,
33
+ attributes,
34
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
35
+ });
36
+ }
37
+ async trackOutcome(operationName, outcome, attributes) {
38
+ this.events.push({
39
+ type: "outcome",
40
+ name: `${operationName}.${outcome}`,
41
+ operation: operationName,
42
+ outcome,
43
+ attributes,
44
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
45
+ });
46
+ }
47
+ async trackValue(name, value, attributes) {
48
+ this.events.push({
49
+ type: "value",
50
+ name,
51
+ value,
52
+ attributes,
53
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
54
+ });
55
+ }
56
+ async shutdown() {
57
+ this.shutdownCalled = true;
58
+ }
59
+ /**
60
+ * Reset captured events (useful between tests)
61
+ */
62
+ reset() {
63
+ this.events = [];
64
+ this.shutdownCalled = false;
65
+ }
66
+ /**
67
+ * Get events by type
68
+ */
69
+ getEventsByType(type) {
70
+ return this.events.filter((e) => e.type === type);
71
+ }
72
+ /**
73
+ * Get events by name
74
+ */
75
+ getEventsByName(name) {
76
+ return this.events.filter((e) => e.name === name);
77
+ }
78
+ /**
79
+ * Get funnel events for a specific funnel
80
+ */
81
+ getFunnelEvents(funnelName) {
82
+ return this.events.filter((e) => e.type === "funnel" && e.funnel === funnelName);
83
+ }
84
+ /**
85
+ * Get outcome events for a specific operation
86
+ */
87
+ getOutcomeEvents(operationName) {
88
+ return this.events.filter((e) => e.type === "outcome" && e.operation === operationName);
89
+ }
90
+ /**
91
+ * Get value events by metric name
92
+ */
93
+ getValueEvents(metricName) {
94
+ return this.events.filter((e) => e.type === "value" && e.name === metricName);
95
+ }
96
+ /**
97
+ * Assert that an event was tracked
98
+ */
99
+ assertEventTracked(name, attributes) {
100
+ const events = this.getEventsByName(name);
101
+ if (events.length === 0) throw new Error(`No events found with name: ${name}`);
102
+ if (attributes) {
103
+ if (!events.find((event) => {
104
+ if (!event.attributes) return false;
105
+ return Object.entries(attributes).every(([key, value]) => event.attributes[key] === value);
106
+ })) throw new Error(`Event "${name}" found, but no matching attributes: ${JSON.stringify(attributes)}`);
107
+ }
108
+ }
109
+ /**
110
+ * Assert that a funnel step was tracked
111
+ */
112
+ assertFunnelStepTracked(funnelName, step, attributes) {
113
+ const matchingEvent = this.getFunnelEvents(funnelName).find((e) => e.step === step);
114
+ if (!matchingEvent) throw new Error(`Funnel "${funnelName}" step "${step}" was not tracked`);
115
+ if (attributes) {
116
+ if (!Object.entries(attributes).every(([key, value]) => matchingEvent.attributes?.[key] === value)) throw new Error(`Funnel step tracked, but attributes don't match: ${JSON.stringify(attributes)}`);
117
+ }
118
+ }
119
+ /**
120
+ * Assert that an outcome was tracked
121
+ */
122
+ assertOutcomeTracked(operationName, outcome, attributes) {
123
+ const matchingEvent = this.getOutcomeEvents(operationName).find((e) => e.outcome === outcome);
124
+ if (!matchingEvent) throw new Error(`Outcome "${operationName}.${outcome}" was not tracked`);
125
+ if (attributes) {
126
+ if (!Object.entries(attributes).every(([key, value]) => matchingEvent.attributes?.[key] === value)) throw new Error(`Outcome tracked, but attributes don't match: ${JSON.stringify(attributes)}`);
127
+ }
128
+ }
129
+ /**
130
+ * Pretty print all captured events (useful for debugging)
131
+ */
132
+ printEvents() {
133
+ console.log(`\n[${this.name}] Captured ${this.events.length} events:\n`);
134
+ for (const [index, event] of this.events.entries()) {
135
+ console.log(`${index + 1}. [${event.type}] ${event.name}`);
136
+ if (event.attributes) console.log(` Attributes:`, event.attributes);
137
+ if (event.value !== void 0) console.log(` Value: ${event.value}`);
138
+ console.log(` Timestamp: ${event.timestamp}\n`);
139
+ }
140
+ }
141
+ };
142
+
143
+ //#endregion
144
+ export { MockEventSubscriber as t };