@getmicdrop/svelte-components 2.0.4 → 2.0.6
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/dist/components/Alert/Alert.spec.js +170 -170
- package/dist/components/Badges/Badge.spec.js +103 -103
- package/dist/components/BottomSheet/BottomSheet.spec.js +127 -127
- package/dist/components/Breadcrumb/Breadcrumb.spec.js +120 -120
- package/dist/components/Button/Button.spec.js +211 -211
- package/dist/components/Button/ButtonSaveDemo.spec.js +48 -48
- package/dist/components/Calendar/Calendar.spec.js +131 -131
- package/dist/components/Calendar/QuarterView.spec.js +394 -394
- package/dist/components/Card.spec.js +47 -47
- package/dist/components/CropImage/CropImage.spec.js +216 -216
- package/dist/components/DarkModeToggle.spec.js +357 -357
- package/dist/components/ErrorDisplay.spec.js +69 -69
- package/dist/components/FormActions.spec.js +88 -88
- package/dist/components/FormValidationSummary.spec.js +203 -203
- package/dist/components/Icons/Icon.spec.js +175 -175
- package/dist/components/Icons/MoreHori.spec.js +67 -67
- package/dist/components/Icons/WarningIcon.spec.js +30 -30
- package/dist/components/Input/Input.spec.js +573 -573
- package/dist/components/Input/MultiSelect.spec.js +257 -257
- package/dist/components/Input/OTPInput.spec.js +238 -238
- package/dist/components/Input/Select.spec.js +218 -218
- package/dist/components/Layout/BottomNav.spec.js +130 -130
- package/dist/components/Layout/Header.spec.js +203 -203
- package/dist/components/Modal/ConfirmationModal.spec.js +191 -191
- package/dist/components/Modal/Modal.spec.js +95 -95
- package/dist/components/Modal/ModalStateManager.spec.js +100 -100
- package/dist/components/PageLoader.spec.js +54 -54
- package/dist/components/PasswordStrengthIndicator/PasswordStrengthIndicator.spec.js +173 -173
- package/dist/components/PlaceAutocomplete/PlaceAutocomplete.spec.js +300 -300
- package/dist/components/Spinner/Spinner.spec.js +75 -75
- package/dist/components/StatusIndicator/StatusIndicator.spec.js +129 -129
- package/dist/components/Toaster/Toaster.stories.svelte +1 -1
- package/dist/components/Toggle.spec.js +158 -158
- package/dist/components/ValidationError.spec.js +79 -79
- package/dist/components/pages/performers/AvailabilityCalendarModal.spec.js +606 -606
- package/dist/components/pages/performers/AvailabilityCalendarModal.svelte +4 -4
- package/dist/components/pages/performers/ModalShowInfo.spec.js +124 -124
- package/dist/components/pages/performers/ModalShowInfo.svelte +1 -1
- package/dist/components/pages/performers/PageBackButton.spec.js +89 -89
- package/dist/components/pages/performers/SectionHeader.spec.js +75 -75
- package/dist/components/pages/performers/ShowDetails.spec.js +166 -166
- package/dist/components/pages/performers/ShowItemCard.spec.js +793 -793
- package/dist/components/pages/performers/ShowItemCard.svelte +4 -4
- package/dist/components/pages/performers/SwitchOption.spec.js +127 -127
- package/dist/components/pages/performers/VenueInfo.spec.js +167 -167
- package/dist/components/pages/performers/VenueInfo.svelte +1 -1
- package/dist/components/pages/performers/VenueItemCard.spec.js +763 -763
- package/dist/components/pages/performers/VenueItemCard.svelte +4 -4
- package/dist/components/pages/profile/profile-form.spec.js +9 -9
- package/dist/components/pages/settings/tabs/CustomImageDropzone.svelte +3 -3
- package/dist/components/pages/shows/ShowList.spec.js +33 -33
- package/dist/components/pages/shows/TabContent.spec.js +90 -90
- package/dist/components/pages/shows/TabNavigation.spec.js +143 -143
- package/dist/config.js +5 -5
- package/dist/config.spec.js +29 -29
- package/dist/constants/formOptions.js +25 -25
- package/dist/constants/formOptions.spec.js +88 -88
- package/dist/index.js +111 -111
- package/dist/stores/auth.d.ts +9 -0
- package/dist/stores/auth.d.ts.map +1 -0
- package/dist/stores/auth.js +36 -0
- package/dist/stores/auth.spec.d.ts +2 -0
- package/dist/stores/auth.spec.d.ts.map +1 -0
- package/dist/stores/auth.spec.js +139 -0
- package/dist/stores/formDataStore.d.ts +17 -0
- package/dist/stores/formDataStore.d.ts.map +1 -0
- package/dist/stores/formDataStore.js +25 -0
- package/dist/stores/formDataStore.spec.d.ts +2 -0
- package/dist/stores/formDataStore.spec.d.ts.map +1 -0
- package/dist/stores/formDataStore.spec.js +257 -0
- package/dist/stores/formSave.d.ts +24 -0
- package/dist/stores/formSave.d.ts.map +1 -0
- package/dist/stores/formSave.js +132 -0
- package/dist/stores/formSave.spec.d.ts +2 -0
- package/dist/stores/formSave.spec.d.ts.map +1 -0
- package/dist/stores/formSave.spec.js +296 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +0 -0
- package/dist/stores/navigation.d.ts +5 -0
- package/dist/stores/navigation.d.ts.map +1 -0
- package/dist/stores/navigation.js +12 -0
- package/dist/stores/navigation.spec.d.ts +2 -0
- package/dist/stores/navigation.spec.d.ts.map +1 -0
- package/dist/stores/navigation.spec.js +136 -0
- package/dist/stores/toaster.d.ts +4 -0
- package/dist/stores/toaster.d.ts.map +1 -0
- package/dist/stores/toaster.js +13 -0
- package/dist/stores/toaster.spec.d.ts +2 -0
- package/dist/stores/toaster.spec.d.ts.map +1 -0
- package/dist/stores/toaster.spec.js +59 -0
- package/dist/telemetry.js +357 -357
- package/dist/telemetry.server.js +211 -211
- package/dist/telemetry.server.spec.js +434 -434
- package/dist/telemetry.spec.js +660 -660
- package/dist/utils/apiConfig.js +49 -49
- package/dist/utils/apiConfig.spec.js +118 -118
- package/dist/utils/greetings.js +187 -187
- package/dist/utils/greetings.spec.js +337 -337
- package/dist/utils/imageValidation.js +121 -121
- package/dist/utils/imageValidation.spec.js +220 -220
- package/dist/utils/portal.js +25 -25
- package/dist/utils/portal.spec.js +143 -143
- package/dist/utils/utils/utils.js +323 -323
- package/dist/utils/utils/utils.spec.js +698 -698
- package/dist/utils/utils.spec.js +643 -643
- package/package.json +1 -1
|
@@ -1,434 +1,434 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Mock all OpenTelemetry modules
|
|
4
|
-
vi.mock('@opentelemetry/instrumentation', () => ({
|
|
5
|
-
registerInstrumentations: vi.fn(),
|
|
6
|
-
}));
|
|
7
|
-
|
|
8
|
-
vi.mock('@opentelemetry/sdk-node', () => ({
|
|
9
|
-
NodeSDK: vi.fn(() => ({
|
|
10
|
-
start: vi.fn(),
|
|
11
|
-
shutdown: vi.fn(() => Promise.resolve()),
|
|
12
|
-
})),
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
vi.mock('@opentelemetry/exporter-trace-otlp-http', () => ({
|
|
16
|
-
OTLPTraceExporter: vi.fn(),
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
vi.mock('@opentelemetry/resources', () => ({
|
|
20
|
-
Resource: vi.fn(),
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
vi.mock('@opentelemetry/semantic-conventions', () => ({
|
|
24
|
-
SEMRESATTRS_SERVICE_NAME: 'service.name',
|
|
25
|
-
SEMRESATTRS_SERVICE_VERSION: 'service.version',
|
|
26
|
-
SEMRESATTRS_DEPLOYMENT_ENVIRONMENT: 'deployment.environment',
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
vi.mock('@opentelemetry/instrumentation-http', () => ({
|
|
30
|
-
HttpInstrumentation: vi.fn(() => ({})),
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
vi.mock('@opentelemetry/instrumentation-fetch', () => ({
|
|
34
|
-
FetchInstrumentation: vi.fn(() => ({})),
|
|
35
|
-
}));
|
|
36
|
-
|
|
37
|
-
vi.mock('@opentelemetry/auto-instrumentations-node', () => ({
|
|
38
|
-
getNodeAutoInstrumentations: vi.fn(() => []),
|
|
39
|
-
}));
|
|
40
|
-
|
|
41
|
-
const mockSpan = {
|
|
42
|
-
setAttribute: vi.fn(),
|
|
43
|
-
setAttributes: vi.fn(),
|
|
44
|
-
setStatus: vi.fn(),
|
|
45
|
-
recordException: vi.fn(),
|
|
46
|
-
end: vi.fn(),
|
|
47
|
-
spanContext: vi.fn(() => ({
|
|
48
|
-
traceId: 'test-trace-id',
|
|
49
|
-
spanId: 'test-span-id',
|
|
50
|
-
})),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const mockTracer = {
|
|
54
|
-
startSpan: vi.fn(() => mockSpan),
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const mockContext = {
|
|
58
|
-
active: vi.fn(() => ({})),
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const mockPropagation = {
|
|
62
|
-
extract: vi.fn(() => ({})),
|
|
63
|
-
inject: vi.fn(),
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
vi.mock('@opentelemetry/api', () => ({
|
|
67
|
-
trace: {
|
|
68
|
-
getTracer: vi.fn(() => mockTracer),
|
|
69
|
-
},
|
|
70
|
-
context: mockContext,
|
|
71
|
-
propagation: mockPropagation,
|
|
72
|
-
}));
|
|
73
|
-
|
|
74
|
-
describe('telemetry.server.js', () => {
|
|
75
|
-
let telemetryServer;
|
|
76
|
-
|
|
77
|
-
beforeEach(async () => {
|
|
78
|
-
vi.resetModules();
|
|
79
|
-
vi.clearAllMocks();
|
|
80
|
-
|
|
81
|
-
// Ensure we're in a server environment
|
|
82
|
-
delete global.window;
|
|
83
|
-
|
|
84
|
-
// Stub environment variables
|
|
85
|
-
vi.stubEnv('VITE_OTEL_TRACES_ENABLED', 'true');
|
|
86
|
-
vi.stubEnv('VITE_OTEL_SERVICE_NAME', 'test-service');
|
|
87
|
-
vi.stubEnv('VITE_ENVIRONMENT', 'test');
|
|
88
|
-
|
|
89
|
-
telemetryServer = await import('./telemetry.server.js');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
afterEach(() => {
|
|
93
|
-
vi.unstubAllEnvs();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
describe('initServerTelemetry', () => {
|
|
97
|
-
it('initializes server telemetry when enabled', async () => {
|
|
98
|
-
const consoleSpy = vi.spyOn(console, 'log');
|
|
99
|
-
|
|
100
|
-
// Module auto-initializes, calling initServerTelemetry will re-init
|
|
101
|
-
telemetryServer.initServerTelemetry();
|
|
102
|
-
|
|
103
|
-
expect(consoleSpy).toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('logs disabled message when tracing is disabled', async () => {
|
|
107
|
-
vi.resetModules();
|
|
108
|
-
vi.stubEnv('VITE_OTEL_TRACES_ENABLED', 'false');
|
|
109
|
-
|
|
110
|
-
const consoleSpy = vi.spyOn(console, 'log');
|
|
111
|
-
|
|
112
|
-
telemetryServer = await import('./telemetry.server.js');
|
|
113
|
-
telemetryServer.initServerTelemetry();
|
|
114
|
-
|
|
115
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
116
|
-
'[Server Telemetry] Tracing is disabled'
|
|
117
|
-
);
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
describe('createSSRSpan', () => {
|
|
122
|
-
it('creates SSR span with correct name and attributes', () => {
|
|
123
|
-
const mockRequest = {
|
|
124
|
-
method: 'GET',
|
|
125
|
-
url: 'http://localhost:3000/test',
|
|
126
|
-
headers: {
|
|
127
|
-
'user-agent': 'test-agent',
|
|
128
|
-
referer: 'http://localhost:3000/',
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const span = telemetryServer.createSSRSpan(
|
|
133
|
-
'ssr.test',
|
|
134
|
-
mockRequest,
|
|
135
|
-
{ custom: 'attribute' }
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
expect(mockTracer.startSpan).toHaveBeenCalledWith('ssr.test', {
|
|
139
|
-
attributes: {
|
|
140
|
-
'span.kind': 'server',
|
|
141
|
-
'ssr.type': 'page_load',
|
|
142
|
-
'portal.type': 'performers',
|
|
143
|
-
'http.method': 'GET',
|
|
144
|
-
'http.url': 'http://localhost:3000/test',
|
|
145
|
-
'http.user_agent': 'test-agent',
|
|
146
|
-
'http.referer': 'http://localhost:3000/',
|
|
147
|
-
custom: 'attribute',
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
expect(span).toBeDefined();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('handles null request gracefully', () => {
|
|
155
|
-
const span = telemetryServer.createSSRSpan('ssr.null-request', null);
|
|
156
|
-
|
|
157
|
-
expect(mockTracer.startSpan).toHaveBeenCalledWith('ssr.null-request', {
|
|
158
|
-
attributes: {
|
|
159
|
-
'span.kind': 'server',
|
|
160
|
-
'ssr.type': 'page_load',
|
|
161
|
-
'portal.type': 'performers',
|
|
162
|
-
'http.method': 'GET',
|
|
163
|
-
'http.url': undefined,
|
|
164
|
-
'http.user_agent': undefined,
|
|
165
|
-
'http.referer': undefined,
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
expect(span).toBeDefined();
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
describe('trackPerformerSSRDataLoad', () => {
|
|
174
|
-
it('wraps load function and tracks successful execution', async () => {
|
|
175
|
-
const mockLoadFn = vi.fn().mockResolvedValue({
|
|
176
|
-
performer: { id: 1, name: 'Test Performer', email: 'test@test.com' },
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const mockEvent = {
|
|
180
|
-
request: {
|
|
181
|
-
method: 'GET',
|
|
182
|
-
url: 'http://localhost:3000/performer/1',
|
|
183
|
-
headers: {},
|
|
184
|
-
},
|
|
185
|
-
route: { id: '/performer/[id]' },
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
const wrappedFn = telemetryServer.trackPerformerSSRDataLoad(
|
|
189
|
-
mockLoadFn,
|
|
190
|
-
'performer-load'
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
const result = await wrappedFn(mockEvent);
|
|
194
|
-
|
|
195
|
-
expect(mockLoadFn).toHaveBeenCalledWith(mockEvent);
|
|
196
|
-
expect(result.performer.id).toBe(1);
|
|
197
|
-
expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: 1 });
|
|
198
|
-
expect(mockSpan.setAttributes).toHaveBeenCalledWith({
|
|
199
|
-
'performer.id': 1,
|
|
200
|
-
'performer.name': 'Test Performer',
|
|
201
|
-
'performer.email': 'test@test.com',
|
|
202
|
-
});
|
|
203
|
-
expect(mockSpan.end).toHaveBeenCalled();
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it('tracks errors and re-throws them', async () => {
|
|
207
|
-
const testError = new Error('Load failed');
|
|
208
|
-
const mockLoadFn = vi.fn().mockRejectedValue(testError);
|
|
209
|
-
|
|
210
|
-
const mockEvent = {
|
|
211
|
-
request: {
|
|
212
|
-
method: 'GET',
|
|
213
|
-
url: 'http://localhost:3000/test',
|
|
214
|
-
headers: {},
|
|
215
|
-
},
|
|
216
|
-
route: { id: '/test' },
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const wrappedFn = telemetryServer.trackPerformerSSRDataLoad(
|
|
220
|
-
mockLoadFn,
|
|
221
|
-
'test-load'
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
await expect(wrappedFn(mockEvent)).rejects.toThrow('Load failed');
|
|
225
|
-
|
|
226
|
-
expect(mockSpan.recordException).toHaveBeenCalledWith(testError);
|
|
227
|
-
expect(mockSpan.setStatus).toHaveBeenCalledWith({
|
|
228
|
-
code: 2,
|
|
229
|
-
message: 'Load failed',
|
|
230
|
-
});
|
|
231
|
-
expect(mockSpan.end).toHaveBeenCalled();
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('handles results without performer data', async () => {
|
|
235
|
-
const mockLoadFn = vi.fn().mockResolvedValue({ data: 'test' });
|
|
236
|
-
|
|
237
|
-
const mockEvent = {
|
|
238
|
-
request: {
|
|
239
|
-
method: 'GET',
|
|
240
|
-
url: 'http://localhost:3000/test',
|
|
241
|
-
headers: {},
|
|
242
|
-
},
|
|
243
|
-
route: { id: '/test' },
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const wrappedFn = telemetryServer.trackPerformerSSRDataLoad(
|
|
247
|
-
mockLoadFn,
|
|
248
|
-
'test-load'
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
const result = await wrappedFn(mockEvent);
|
|
252
|
-
|
|
253
|
-
expect(result.data).toBe('test');
|
|
254
|
-
expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: 1 });
|
|
255
|
-
// setAttributes should not be called for performer data
|
|
256
|
-
expect(mockSpan.end).toHaveBeenCalled();
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
describe('extractTraceContext', () => {
|
|
261
|
-
it('extracts trace context from request headers', () => {
|
|
262
|
-
const mockRequest = {
|
|
263
|
-
headers: new Map([
|
|
264
|
-
['x-b3-traceid', 'test-trace'],
|
|
265
|
-
['x-b3-spanid', 'test-span'],
|
|
266
|
-
]),
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
mockRequest.headers.entries = function () {
|
|
270
|
-
return this[Symbol.iterator]();
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
telemetryServer.extractTraceContext(mockRequest);
|
|
274
|
-
|
|
275
|
-
expect(mockPropagation.extract).toHaveBeenCalled();
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it('handles null request', () => {
|
|
279
|
-
const result = telemetryServer.extractTraceContext(null);
|
|
280
|
-
|
|
281
|
-
expect(mockPropagation.extract).toHaveBeenCalled();
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('handles request without headers', () => {
|
|
285
|
-
const mockRequest = {};
|
|
286
|
-
|
|
287
|
-
const result = telemetryServer.extractTraceContext(mockRequest);
|
|
288
|
-
|
|
289
|
-
expect(mockPropagation.extract).toHaveBeenCalled();
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
describe('injectTraceContext', () => {
|
|
294
|
-
it('injects trace context into response headers', () => {
|
|
295
|
-
const mockResponse = {
|
|
296
|
-
headers: {
|
|
297
|
-
set: vi.fn(),
|
|
298
|
-
},
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
mockPropagation.inject.mockImplementation((ctx, headers) => {
|
|
302
|
-
headers['x-b3-traceid'] = 'injected-trace';
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
telemetryServer.injectTraceContext(mockResponse, mockSpan);
|
|
306
|
-
|
|
307
|
-
expect(mockPropagation.inject).toHaveBeenCalled();
|
|
308
|
-
expect(mockResponse.headers.set).toHaveBeenCalledWith(
|
|
309
|
-
'X-Trace-Id',
|
|
310
|
-
'test-trace-id'
|
|
311
|
-
);
|
|
312
|
-
expect(mockResponse.headers.set).toHaveBeenCalledWith(
|
|
313
|
-
'X-Span-Id',
|
|
314
|
-
'test-span-id'
|
|
315
|
-
);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it('handles null span context', () => {
|
|
319
|
-
const mockResponse = {
|
|
320
|
-
headers: {
|
|
321
|
-
set: vi.fn(),
|
|
322
|
-
},
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
const nullContextSpan = {
|
|
326
|
-
spanContext: vi.fn(() => null),
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
// Should not throw
|
|
330
|
-
expect(() =>
|
|
331
|
-
telemetryServer.injectTraceContext(mockResponse, nullContextSpan)
|
|
332
|
-
).not.toThrow();
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
it('handles response without headers', () => {
|
|
336
|
-
const mockResponse = {};
|
|
337
|
-
|
|
338
|
-
// Should not throw
|
|
339
|
-
expect(() =>
|
|
340
|
-
telemetryServer.injectTraceContext(mockResponse, mockSpan)
|
|
341
|
-
).not.toThrow();
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
describe('shutdownServerTelemetry', () => {
|
|
346
|
-
it('shuts down SDK gracefully', async () => {
|
|
347
|
-
const consoleSpy = vi.spyOn(console, 'log');
|
|
348
|
-
|
|
349
|
-
await telemetryServer.shutdownServerTelemetry();
|
|
350
|
-
|
|
351
|
-
// May or may not log depending on SDK state
|
|
352
|
-
expect(true).toBe(true);
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
describe('performersPortalTelemetry', () => {
|
|
357
|
-
it('exports wrapLoad helper', () => {
|
|
358
|
-
expect(telemetryServer.performersPortalTelemetry.wrapLoad).toBeDefined();
|
|
359
|
-
expect(
|
|
360
|
-
typeof telemetryServer.performersPortalTelemetry.wrapLoad
|
|
361
|
-
).toBe('function');
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
it('exports wrapAction helper', () => {
|
|
365
|
-
expect(telemetryServer.performersPortalTelemetry.wrapAction).toBeDefined();
|
|
366
|
-
expect(
|
|
367
|
-
typeof telemetryServer.performersPortalTelemetry.wrapAction
|
|
368
|
-
).toBe('function');
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
it('wrapLoad returns wrapped function', () => {
|
|
372
|
-
const mockFn = vi.fn();
|
|
373
|
-
const wrapped = telemetryServer.performersPortalTelemetry.wrapLoad(
|
|
374
|
-
mockFn,
|
|
375
|
-
'test'
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
expect(typeof wrapped).toBe('function');
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
it('wrapAction handles successful action', async () => {
|
|
382
|
-
const mockActionFn = vi.fn().mockResolvedValue({ success: true });
|
|
383
|
-
|
|
384
|
-
const mockEvent = {
|
|
385
|
-
request: {
|
|
386
|
-
method: 'POST',
|
|
387
|
-
url: 'http://localhost:3000/action',
|
|
388
|
-
headers: {},
|
|
389
|
-
},
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
const wrappedAction =
|
|
393
|
-
telemetryServer.performersPortalTelemetry.wrapAction(
|
|
394
|
-
mockActionFn,
|
|
395
|
-
'test-action'
|
|
396
|
-
);
|
|
397
|
-
|
|
398
|
-
const result = await wrappedAction(mockEvent);
|
|
399
|
-
|
|
400
|
-
expect(mockActionFn).toHaveBeenCalledWith(mockEvent);
|
|
401
|
-
expect(result.success).toBe(true);
|
|
402
|
-
expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: 1 });
|
|
403
|
-
expect(mockSpan.end).toHaveBeenCalled();
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it('wrapAction handles action errors', async () => {
|
|
407
|
-
const testError = new Error('Action failed');
|
|
408
|
-
const mockActionFn = vi.fn().mockRejectedValue(testError);
|
|
409
|
-
|
|
410
|
-
const mockEvent = {
|
|
411
|
-
request: {
|
|
412
|
-
method: 'POST',
|
|
413
|
-
url: 'http://localhost:3000/action',
|
|
414
|
-
headers: {},
|
|
415
|
-
},
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
const wrappedAction =
|
|
419
|
-
telemetryServer.performersPortalTelemetry.wrapAction(
|
|
420
|
-
mockActionFn,
|
|
421
|
-
'failing-action'
|
|
422
|
-
);
|
|
423
|
-
|
|
424
|
-
await expect(wrappedAction(mockEvent)).rejects.toThrow('Action failed');
|
|
425
|
-
|
|
426
|
-
expect(mockSpan.recordException).toHaveBeenCalledWith(testError);
|
|
427
|
-
expect(mockSpan.setStatus).toHaveBeenCalledWith({
|
|
428
|
-
code: 2,
|
|
429
|
-
message: 'Action failed',
|
|
430
|
-
});
|
|
431
|
-
expect(mockSpan.end).toHaveBeenCalled();
|
|
432
|
-
});
|
|
433
|
-
});
|
|
434
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Mock all OpenTelemetry modules
|
|
4
|
+
vi.mock('@opentelemetry/instrumentation', () => ({
|
|
5
|
+
registerInstrumentations: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
vi.mock('@opentelemetry/sdk-node', () => ({
|
|
9
|
+
NodeSDK: vi.fn(() => ({
|
|
10
|
+
start: vi.fn(),
|
|
11
|
+
shutdown: vi.fn(() => Promise.resolve()),
|
|
12
|
+
})),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock('@opentelemetry/exporter-trace-otlp-http', () => ({
|
|
16
|
+
OTLPTraceExporter: vi.fn(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock('@opentelemetry/resources', () => ({
|
|
20
|
+
Resource: vi.fn(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
vi.mock('@opentelemetry/semantic-conventions', () => ({
|
|
24
|
+
SEMRESATTRS_SERVICE_NAME: 'service.name',
|
|
25
|
+
SEMRESATTRS_SERVICE_VERSION: 'service.version',
|
|
26
|
+
SEMRESATTRS_DEPLOYMENT_ENVIRONMENT: 'deployment.environment',
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
vi.mock('@opentelemetry/instrumentation-http', () => ({
|
|
30
|
+
HttpInstrumentation: vi.fn(() => ({})),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock('@opentelemetry/instrumentation-fetch', () => ({
|
|
34
|
+
FetchInstrumentation: vi.fn(() => ({})),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
vi.mock('@opentelemetry/auto-instrumentations-node', () => ({
|
|
38
|
+
getNodeAutoInstrumentations: vi.fn(() => []),
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
const mockSpan = {
|
|
42
|
+
setAttribute: vi.fn(),
|
|
43
|
+
setAttributes: vi.fn(),
|
|
44
|
+
setStatus: vi.fn(),
|
|
45
|
+
recordException: vi.fn(),
|
|
46
|
+
end: vi.fn(),
|
|
47
|
+
spanContext: vi.fn(() => ({
|
|
48
|
+
traceId: 'test-trace-id',
|
|
49
|
+
spanId: 'test-span-id',
|
|
50
|
+
})),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const mockTracer = {
|
|
54
|
+
startSpan: vi.fn(() => mockSpan),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const mockContext = {
|
|
58
|
+
active: vi.fn(() => ({})),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const mockPropagation = {
|
|
62
|
+
extract: vi.fn(() => ({})),
|
|
63
|
+
inject: vi.fn(),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
vi.mock('@opentelemetry/api', () => ({
|
|
67
|
+
trace: {
|
|
68
|
+
getTracer: vi.fn(() => mockTracer),
|
|
69
|
+
},
|
|
70
|
+
context: mockContext,
|
|
71
|
+
propagation: mockPropagation,
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
describe('telemetry.server.js', () => {
|
|
75
|
+
let telemetryServer;
|
|
76
|
+
|
|
77
|
+
beforeEach(async () => {
|
|
78
|
+
vi.resetModules();
|
|
79
|
+
vi.clearAllMocks();
|
|
80
|
+
|
|
81
|
+
// Ensure we're in a server environment
|
|
82
|
+
delete global.window;
|
|
83
|
+
|
|
84
|
+
// Stub environment variables
|
|
85
|
+
vi.stubEnv('VITE_OTEL_TRACES_ENABLED', 'true');
|
|
86
|
+
vi.stubEnv('VITE_OTEL_SERVICE_NAME', 'test-service');
|
|
87
|
+
vi.stubEnv('VITE_ENVIRONMENT', 'test');
|
|
88
|
+
|
|
89
|
+
telemetryServer = await import('./telemetry.server.js');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
afterEach(() => {
|
|
93
|
+
vi.unstubAllEnvs();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('initServerTelemetry', () => {
|
|
97
|
+
it('initializes server telemetry when enabled', async () => {
|
|
98
|
+
const consoleSpy = vi.spyOn(console, 'log');
|
|
99
|
+
|
|
100
|
+
// Module auto-initializes, calling initServerTelemetry will re-init
|
|
101
|
+
telemetryServer.initServerTelemetry();
|
|
102
|
+
|
|
103
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('logs disabled message when tracing is disabled', async () => {
|
|
107
|
+
vi.resetModules();
|
|
108
|
+
vi.stubEnv('VITE_OTEL_TRACES_ENABLED', 'false');
|
|
109
|
+
|
|
110
|
+
const consoleSpy = vi.spyOn(console, 'log');
|
|
111
|
+
|
|
112
|
+
telemetryServer = await import('./telemetry.server.js');
|
|
113
|
+
telemetryServer.initServerTelemetry();
|
|
114
|
+
|
|
115
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
116
|
+
'[Server Telemetry] Tracing is disabled'
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('createSSRSpan', () => {
|
|
122
|
+
it('creates SSR span with correct name and attributes', () => {
|
|
123
|
+
const mockRequest = {
|
|
124
|
+
method: 'GET',
|
|
125
|
+
url: 'http://localhost:3000/test',
|
|
126
|
+
headers: {
|
|
127
|
+
'user-agent': 'test-agent',
|
|
128
|
+
referer: 'http://localhost:3000/',
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const span = telemetryServer.createSSRSpan(
|
|
133
|
+
'ssr.test',
|
|
134
|
+
mockRequest,
|
|
135
|
+
{ custom: 'attribute' }
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(mockTracer.startSpan).toHaveBeenCalledWith('ssr.test', {
|
|
139
|
+
attributes: {
|
|
140
|
+
'span.kind': 'server',
|
|
141
|
+
'ssr.type': 'page_load',
|
|
142
|
+
'portal.type': 'performers',
|
|
143
|
+
'http.method': 'GET',
|
|
144
|
+
'http.url': 'http://localhost:3000/test',
|
|
145
|
+
'http.user_agent': 'test-agent',
|
|
146
|
+
'http.referer': 'http://localhost:3000/',
|
|
147
|
+
custom: 'attribute',
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(span).toBeDefined();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('handles null request gracefully', () => {
|
|
155
|
+
const span = telemetryServer.createSSRSpan('ssr.null-request', null);
|
|
156
|
+
|
|
157
|
+
expect(mockTracer.startSpan).toHaveBeenCalledWith('ssr.null-request', {
|
|
158
|
+
attributes: {
|
|
159
|
+
'span.kind': 'server',
|
|
160
|
+
'ssr.type': 'page_load',
|
|
161
|
+
'portal.type': 'performers',
|
|
162
|
+
'http.method': 'GET',
|
|
163
|
+
'http.url': undefined,
|
|
164
|
+
'http.user_agent': undefined,
|
|
165
|
+
'http.referer': undefined,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
expect(span).toBeDefined();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('trackPerformerSSRDataLoad', () => {
|
|
174
|
+
it('wraps load function and tracks successful execution', async () => {
|
|
175
|
+
const mockLoadFn = vi.fn().mockResolvedValue({
|
|
176
|
+
performer: { id: 1, name: 'Test Performer', email: 'test@test.com' },
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const mockEvent = {
|
|
180
|
+
request: {
|
|
181
|
+
method: 'GET',
|
|
182
|
+
url: 'http://localhost:3000/performer/1',
|
|
183
|
+
headers: {},
|
|
184
|
+
},
|
|
185
|
+
route: { id: '/performer/[id]' },
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const wrappedFn = telemetryServer.trackPerformerSSRDataLoad(
|
|
189
|
+
mockLoadFn,
|
|
190
|
+
'performer-load'
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const result = await wrappedFn(mockEvent);
|
|
194
|
+
|
|
195
|
+
expect(mockLoadFn).toHaveBeenCalledWith(mockEvent);
|
|
196
|
+
expect(result.performer.id).toBe(1);
|
|
197
|
+
expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: 1 });
|
|
198
|
+
expect(mockSpan.setAttributes).toHaveBeenCalledWith({
|
|
199
|
+
'performer.id': 1,
|
|
200
|
+
'performer.name': 'Test Performer',
|
|
201
|
+
'performer.email': 'test@test.com',
|
|
202
|
+
});
|
|
203
|
+
expect(mockSpan.end).toHaveBeenCalled();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('tracks errors and re-throws them', async () => {
|
|
207
|
+
const testError = new Error('Load failed');
|
|
208
|
+
const mockLoadFn = vi.fn().mockRejectedValue(testError);
|
|
209
|
+
|
|
210
|
+
const mockEvent = {
|
|
211
|
+
request: {
|
|
212
|
+
method: 'GET',
|
|
213
|
+
url: 'http://localhost:3000/test',
|
|
214
|
+
headers: {},
|
|
215
|
+
},
|
|
216
|
+
route: { id: '/test' },
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const wrappedFn = telemetryServer.trackPerformerSSRDataLoad(
|
|
220
|
+
mockLoadFn,
|
|
221
|
+
'test-load'
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
await expect(wrappedFn(mockEvent)).rejects.toThrow('Load failed');
|
|
225
|
+
|
|
226
|
+
expect(mockSpan.recordException).toHaveBeenCalledWith(testError);
|
|
227
|
+
expect(mockSpan.setStatus).toHaveBeenCalledWith({
|
|
228
|
+
code: 2,
|
|
229
|
+
message: 'Load failed',
|
|
230
|
+
});
|
|
231
|
+
expect(mockSpan.end).toHaveBeenCalled();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('handles results without performer data', async () => {
|
|
235
|
+
const mockLoadFn = vi.fn().mockResolvedValue({ data: 'test' });
|
|
236
|
+
|
|
237
|
+
const mockEvent = {
|
|
238
|
+
request: {
|
|
239
|
+
method: 'GET',
|
|
240
|
+
url: 'http://localhost:3000/test',
|
|
241
|
+
headers: {},
|
|
242
|
+
},
|
|
243
|
+
route: { id: '/test' },
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const wrappedFn = telemetryServer.trackPerformerSSRDataLoad(
|
|
247
|
+
mockLoadFn,
|
|
248
|
+
'test-load'
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const result = await wrappedFn(mockEvent);
|
|
252
|
+
|
|
253
|
+
expect(result.data).toBe('test');
|
|
254
|
+
expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: 1 });
|
|
255
|
+
// setAttributes should not be called for performer data
|
|
256
|
+
expect(mockSpan.end).toHaveBeenCalled();
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe('extractTraceContext', () => {
|
|
261
|
+
it('extracts trace context from request headers', () => {
|
|
262
|
+
const mockRequest = {
|
|
263
|
+
headers: new Map([
|
|
264
|
+
['x-b3-traceid', 'test-trace'],
|
|
265
|
+
['x-b3-spanid', 'test-span'],
|
|
266
|
+
]),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
mockRequest.headers.entries = function () {
|
|
270
|
+
return this[Symbol.iterator]();
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
telemetryServer.extractTraceContext(mockRequest);
|
|
274
|
+
|
|
275
|
+
expect(mockPropagation.extract).toHaveBeenCalled();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('handles null request', () => {
|
|
279
|
+
const result = telemetryServer.extractTraceContext(null);
|
|
280
|
+
|
|
281
|
+
expect(mockPropagation.extract).toHaveBeenCalled();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('handles request without headers', () => {
|
|
285
|
+
const mockRequest = {};
|
|
286
|
+
|
|
287
|
+
const result = telemetryServer.extractTraceContext(mockRequest);
|
|
288
|
+
|
|
289
|
+
expect(mockPropagation.extract).toHaveBeenCalled();
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe('injectTraceContext', () => {
|
|
294
|
+
it('injects trace context into response headers', () => {
|
|
295
|
+
const mockResponse = {
|
|
296
|
+
headers: {
|
|
297
|
+
set: vi.fn(),
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
mockPropagation.inject.mockImplementation((ctx, headers) => {
|
|
302
|
+
headers['x-b3-traceid'] = 'injected-trace';
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
telemetryServer.injectTraceContext(mockResponse, mockSpan);
|
|
306
|
+
|
|
307
|
+
expect(mockPropagation.inject).toHaveBeenCalled();
|
|
308
|
+
expect(mockResponse.headers.set).toHaveBeenCalledWith(
|
|
309
|
+
'X-Trace-Id',
|
|
310
|
+
'test-trace-id'
|
|
311
|
+
);
|
|
312
|
+
expect(mockResponse.headers.set).toHaveBeenCalledWith(
|
|
313
|
+
'X-Span-Id',
|
|
314
|
+
'test-span-id'
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('handles null span context', () => {
|
|
319
|
+
const mockResponse = {
|
|
320
|
+
headers: {
|
|
321
|
+
set: vi.fn(),
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const nullContextSpan = {
|
|
326
|
+
spanContext: vi.fn(() => null),
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
// Should not throw
|
|
330
|
+
expect(() =>
|
|
331
|
+
telemetryServer.injectTraceContext(mockResponse, nullContextSpan)
|
|
332
|
+
).not.toThrow();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('handles response without headers', () => {
|
|
336
|
+
const mockResponse = {};
|
|
337
|
+
|
|
338
|
+
// Should not throw
|
|
339
|
+
expect(() =>
|
|
340
|
+
telemetryServer.injectTraceContext(mockResponse, mockSpan)
|
|
341
|
+
).not.toThrow();
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
describe('shutdownServerTelemetry', () => {
|
|
346
|
+
it('shuts down SDK gracefully', async () => {
|
|
347
|
+
const consoleSpy = vi.spyOn(console, 'log');
|
|
348
|
+
|
|
349
|
+
await telemetryServer.shutdownServerTelemetry();
|
|
350
|
+
|
|
351
|
+
// May or may not log depending on SDK state
|
|
352
|
+
expect(true).toBe(true);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe('performersPortalTelemetry', () => {
|
|
357
|
+
it('exports wrapLoad helper', () => {
|
|
358
|
+
expect(telemetryServer.performersPortalTelemetry.wrapLoad).toBeDefined();
|
|
359
|
+
expect(
|
|
360
|
+
typeof telemetryServer.performersPortalTelemetry.wrapLoad
|
|
361
|
+
).toBe('function');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('exports wrapAction helper', () => {
|
|
365
|
+
expect(telemetryServer.performersPortalTelemetry.wrapAction).toBeDefined();
|
|
366
|
+
expect(
|
|
367
|
+
typeof telemetryServer.performersPortalTelemetry.wrapAction
|
|
368
|
+
).toBe('function');
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('wrapLoad returns wrapped function', () => {
|
|
372
|
+
const mockFn = vi.fn();
|
|
373
|
+
const wrapped = telemetryServer.performersPortalTelemetry.wrapLoad(
|
|
374
|
+
mockFn,
|
|
375
|
+
'test'
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
expect(typeof wrapped).toBe('function');
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('wrapAction handles successful action', async () => {
|
|
382
|
+
const mockActionFn = vi.fn().mockResolvedValue({ success: true });
|
|
383
|
+
|
|
384
|
+
const mockEvent = {
|
|
385
|
+
request: {
|
|
386
|
+
method: 'POST',
|
|
387
|
+
url: 'http://localhost:3000/action',
|
|
388
|
+
headers: {},
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const wrappedAction =
|
|
393
|
+
telemetryServer.performersPortalTelemetry.wrapAction(
|
|
394
|
+
mockActionFn,
|
|
395
|
+
'test-action'
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
const result = await wrappedAction(mockEvent);
|
|
399
|
+
|
|
400
|
+
expect(mockActionFn).toHaveBeenCalledWith(mockEvent);
|
|
401
|
+
expect(result.success).toBe(true);
|
|
402
|
+
expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: 1 });
|
|
403
|
+
expect(mockSpan.end).toHaveBeenCalled();
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('wrapAction handles action errors', async () => {
|
|
407
|
+
const testError = new Error('Action failed');
|
|
408
|
+
const mockActionFn = vi.fn().mockRejectedValue(testError);
|
|
409
|
+
|
|
410
|
+
const mockEvent = {
|
|
411
|
+
request: {
|
|
412
|
+
method: 'POST',
|
|
413
|
+
url: 'http://localhost:3000/action',
|
|
414
|
+
headers: {},
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
const wrappedAction =
|
|
419
|
+
telemetryServer.performersPortalTelemetry.wrapAction(
|
|
420
|
+
mockActionFn,
|
|
421
|
+
'failing-action'
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
await expect(wrappedAction(mockEvent)).rejects.toThrow('Action failed');
|
|
425
|
+
|
|
426
|
+
expect(mockSpan.recordException).toHaveBeenCalledWith(testError);
|
|
427
|
+
expect(mockSpan.setStatus).toHaveBeenCalledWith({
|
|
428
|
+
code: 2,
|
|
429
|
+
message: 'Action failed',
|
|
430
|
+
});
|
|
431
|
+
expect(mockSpan.end).toHaveBeenCalled();
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
});
|