codebuff 1.0.332 → 1.0.334
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/__tests__/display.test.js +1 -1
- package/dist/__tests__/display.test.js.map +1 -1
- package/dist/__tests__/rage-detectors.test.d.ts +1 -0
- package/dist/__tests__/rage-detectors.test.js +127 -0
- package/dist/__tests__/rage-detectors.test.js.map +1 -0
- package/dist/checkpoints/file-manager.js +4 -1
- package/dist/checkpoints/file-manager.js.map +1 -1
- package/dist/cli.js +43 -5
- package/dist/cli.js.map +1 -1
- package/dist/code-map/tsconfig.tsbuildinfo +1 -1
- package/dist/common/constants/analytics-events.d.ts +2 -0
- package/dist/common/constants/analytics-events.d.ts.map +1 -1
- package/dist/common/constants/analytics-events.js +2 -0
- package/dist/common/constants/analytics-events.js.map +1 -1
- package/dist/common/json-config/__tests__/__snapshots__/stringify-schema.test.js.snap +144 -0
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/rage-detectors.d.ts +15 -0
- package/dist/rage-detectors.js +55 -0
- package/dist/rage-detectors.js.map +1 -0
- package/dist/utils/__tests__/background-process-manager.test.js +21 -22
- package/dist/utils/__tests__/background-process-manager.test.js.map +1 -1
- package/dist/utils/__tests__/rage-detector.test.d.ts +1 -0
- package/dist/utils/__tests__/rage-detector.test.js +450 -0
- package/dist/utils/__tests__/rage-detector.test.js.map +1 -0
- package/dist/utils/analytics.js +13 -7
- package/dist/utils/analytics.js.map +1 -1
- package/dist/utils/rage-detector.d.ts +32 -0
- package/dist/utils/rage-detector.js +143 -0
- package/dist/utils/rage-detector.js.map +1 -0
- package/dist/utils/spinner.d.ts +1 -0
- package/dist/utils/spinner.js +9 -0
- package/dist/utils/spinner.js.map +1 -1
- package/dist/utils/with-hang-detection.d.ts +1 -0
- package/dist/utils/with-hang-detection.js +18 -0
- package/dist/utils/with-hang-detection.js.map +1 -0
- package/package.json +1 -1
|
@@ -23,10 +23,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
// @ts-ignore
|
|
26
|
+
// @ts-ignore
|
|
27
27
|
const bun_test_1 = require("bun:test");
|
|
28
|
-
// @ts-ignore: bun:test types aren't available
|
|
29
|
-
const bun_test_2 = require("bun:test");
|
|
30
28
|
// Mock the child process
|
|
31
29
|
const mockChildProcess = {
|
|
32
30
|
exitCode: null,
|
|
@@ -37,17 +35,18 @@ const isCI = process.env.CODEBUFF_GITHUB_ACTIONS === 'true';
|
|
|
37
35
|
// Skip tests entirely in CI
|
|
38
36
|
if (!isCI) {
|
|
39
37
|
// Wrap the dynamic import and tests in an async IIFE to avoid top-level await
|
|
38
|
+
;
|
|
40
39
|
(async () => {
|
|
41
40
|
// Only import the implementation if not in CI
|
|
42
41
|
const { getBackgroundProcessInfoString } = await Promise.resolve().then(() => __importStar(require('../../background-process-manager')));
|
|
43
|
-
(0,
|
|
42
|
+
(0, bun_test_1.describe)('getBackgroundProcessInfoString', () => {
|
|
44
43
|
let dateNowSpy;
|
|
45
44
|
const currentTime = 3000;
|
|
46
|
-
(0,
|
|
47
|
-
(0,
|
|
45
|
+
(0, bun_test_1.beforeEach)(() => {
|
|
46
|
+
(0, bun_test_1.spyOn)(Date, 'now').mockReturnValue(currentTime);
|
|
48
47
|
});
|
|
49
|
-
(0,
|
|
50
|
-
|
|
48
|
+
(0, bun_test_1.afterEach)(() => {
|
|
49
|
+
bun_test_1.mock.restore();
|
|
51
50
|
});
|
|
52
51
|
(0, bun_test_1.test)('formats a running process correctly', () => {
|
|
53
52
|
const startTime = 1000;
|
|
@@ -66,7 +65,7 @@ if (!isCI) {
|
|
|
66
65
|
lastReportedStatus: null,
|
|
67
66
|
};
|
|
68
67
|
const result = getBackgroundProcessInfoString(info);
|
|
69
|
-
(0,
|
|
68
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
70
69
|
});
|
|
71
70
|
(0, bun_test_1.test)('formats a completed process correctly', () => {
|
|
72
71
|
const startTime = 1000;
|
|
@@ -90,7 +89,7 @@ if (!isCI) {
|
|
|
90
89
|
lastReportedStatus: null,
|
|
91
90
|
};
|
|
92
91
|
const result = getBackgroundProcessInfoString(info);
|
|
93
|
-
(0,
|
|
92
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
94
93
|
});
|
|
95
94
|
(0, bun_test_1.test)('formats an errored process correctly', () => {
|
|
96
95
|
const startTime = 1000;
|
|
@@ -115,7 +114,7 @@ if (!isCI) {
|
|
|
115
114
|
lastReportedStatus: null,
|
|
116
115
|
};
|
|
117
116
|
const result = getBackgroundProcessInfoString(info);
|
|
118
|
-
(0,
|
|
117
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
119
118
|
});
|
|
120
119
|
(0, bun_test_1.test)('returns empty string for completed process with no changes', () => {
|
|
121
120
|
const startTime = 1000;
|
|
@@ -135,7 +134,7 @@ if (!isCI) {
|
|
|
135
134
|
lastReportedStatus: 'completed',
|
|
136
135
|
};
|
|
137
136
|
const result = getBackgroundProcessInfoString(info);
|
|
138
|
-
(0,
|
|
137
|
+
(0, bun_test_1.expect)(result).toBe('');
|
|
139
138
|
});
|
|
140
139
|
(0, bun_test_1.test)('handles new output since last report', () => {
|
|
141
140
|
const startTime = 1000;
|
|
@@ -155,7 +154,7 @@ if (!isCI) {
|
|
|
155
154
|
lastReportedStatus: 'completed',
|
|
156
155
|
};
|
|
157
156
|
const result = getBackgroundProcessInfoString(info);
|
|
158
|
-
(0,
|
|
157
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
159
158
|
});
|
|
160
159
|
(0, bun_test_1.test)('handles no new content', () => {
|
|
161
160
|
const startTime = 1000;
|
|
@@ -175,7 +174,7 @@ if (!isCI) {
|
|
|
175
174
|
lastReportedStatus: 'running',
|
|
176
175
|
};
|
|
177
176
|
const result = getBackgroundProcessInfoString(info);
|
|
178
|
-
(0,
|
|
177
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
179
178
|
});
|
|
180
179
|
(0, bun_test_1.test)('handles new stderr without when no previous stderr', () => {
|
|
181
180
|
const startTime = 1000;
|
|
@@ -195,7 +194,7 @@ if (!isCI) {
|
|
|
195
194
|
lastReportedStatus: null,
|
|
196
195
|
};
|
|
197
196
|
const result = getBackgroundProcessInfoString(info);
|
|
198
|
-
(0,
|
|
197
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
199
198
|
});
|
|
200
199
|
(0, bun_test_1.test)('handles new stdout without when no previous stdout', () => {
|
|
201
200
|
const startTime = 1000;
|
|
@@ -214,7 +213,7 @@ if (!isCI) {
|
|
|
214
213
|
lastReportedStatus: null,
|
|
215
214
|
};
|
|
216
215
|
const result = getBackgroundProcessInfoString(info);
|
|
217
|
-
(0,
|
|
216
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
218
217
|
});
|
|
219
218
|
(0, bun_test_1.test)('reports completed process with new stderr even if stdout unchanged', () => {
|
|
220
219
|
const startTime = 1000;
|
|
@@ -234,7 +233,7 @@ if (!isCI) {
|
|
|
234
233
|
lastReportedStatus: 'completed',
|
|
235
234
|
};
|
|
236
235
|
const result = getBackgroundProcessInfoString(info);
|
|
237
|
-
(0,
|
|
236
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
238
237
|
});
|
|
239
238
|
(0, bun_test_1.test)('reports completed process with new stdout even if stderr unchanged', () => {
|
|
240
239
|
const startTime = 1000;
|
|
@@ -254,7 +253,7 @@ if (!isCI) {
|
|
|
254
253
|
lastReportedStatus: 'completed',
|
|
255
254
|
};
|
|
256
255
|
const result = getBackgroundProcessInfoString(info);
|
|
257
|
-
(0,
|
|
256
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
258
257
|
});
|
|
259
258
|
(0, bun_test_1.test)('reports process when status changes even without output changes', () => {
|
|
260
259
|
const startTime = 1000;
|
|
@@ -274,7 +273,7 @@ if (!isCI) {
|
|
|
274
273
|
lastReportedStatus: 'running', // Status changed from running to completed
|
|
275
274
|
};
|
|
276
275
|
const result = getBackgroundProcessInfoString(info);
|
|
277
|
-
(0,
|
|
276
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
278
277
|
});
|
|
279
278
|
(0, bun_test_1.test)('calculates duration from endTime when available', () => {
|
|
280
279
|
const startTime = 1000;
|
|
@@ -294,7 +293,7 @@ if (!isCI) {
|
|
|
294
293
|
lastReportedStatus: null,
|
|
295
294
|
};
|
|
296
295
|
const result = getBackgroundProcessInfoString(info);
|
|
297
|
-
(0,
|
|
296
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
298
297
|
});
|
|
299
298
|
(0, bun_test_1.test)('calculates duration from current time when no endTime', () => {
|
|
300
299
|
const startTime = 1000;
|
|
@@ -313,14 +312,14 @@ if (!isCI) {
|
|
|
313
312
|
lastReportedStatus: null,
|
|
314
313
|
};
|
|
315
314
|
const result = getBackgroundProcessInfoString(info);
|
|
316
|
-
(0,
|
|
315
|
+
(0, bun_test_1.expect)(result).toMatchSnapshot();
|
|
317
316
|
});
|
|
318
317
|
});
|
|
319
318
|
})();
|
|
320
319
|
}
|
|
321
320
|
else {
|
|
322
321
|
// Add a skipped describe block for clarity in test reports
|
|
323
|
-
|
|
322
|
+
bun_test_1.describe.skip('getBackgroundProcessInfoString (skipped in CI)', () => {
|
|
324
323
|
bun_test_1.test.skip('skipped', () => { });
|
|
325
324
|
});
|
|
326
325
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-process-manager.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/background-process-manager.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"background-process-manager.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/background-process-manager.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
const bun_test_1 = require("bun:test");
|
|
5
|
+
const analytics_events_1 = require("../../common/constants/analytics-events");
|
|
6
|
+
const rage_detector_1 = require("../rage-detector");
|
|
7
|
+
// Mock the analytics module
|
|
8
|
+
const mockTrackEvent = (0, bun_test_1.mock)(() => { });
|
|
9
|
+
bun_test_1.mock.module('../analytics', () => ({
|
|
10
|
+
trackEvent: mockTrackEvent,
|
|
11
|
+
}));
|
|
12
|
+
(0, bun_test_1.describe)('Rage Detectors', () => {
|
|
13
|
+
let mockDateNow;
|
|
14
|
+
let mockSetTimeout;
|
|
15
|
+
let mockClearTimeout;
|
|
16
|
+
let currentTime = 0;
|
|
17
|
+
let timeouts = [];
|
|
18
|
+
let timeoutId = 1;
|
|
19
|
+
(0, bun_test_1.beforeEach)(() => {
|
|
20
|
+
bun_test_1.mock.restore();
|
|
21
|
+
mockTrackEvent.mockClear();
|
|
22
|
+
currentTime = 0;
|
|
23
|
+
timeouts = [];
|
|
24
|
+
timeoutId = 1;
|
|
25
|
+
// Mock Date.now
|
|
26
|
+
mockDateNow = (0, bun_test_1.spyOn)(Date, 'now').mockImplementation(() => currentTime);
|
|
27
|
+
// Mock setTimeout
|
|
28
|
+
mockSetTimeout = (0, bun_test_1.spyOn)(global, 'setTimeout').mockImplementation((callback, delay) => {
|
|
29
|
+
const id = timeoutId++;
|
|
30
|
+
timeouts.push({
|
|
31
|
+
callback,
|
|
32
|
+
delay,
|
|
33
|
+
id,
|
|
34
|
+
scheduledTime: currentTime + delay,
|
|
35
|
+
});
|
|
36
|
+
return id;
|
|
37
|
+
});
|
|
38
|
+
// Mock clearTimeout
|
|
39
|
+
mockClearTimeout = (0, bun_test_1.spyOn)(global, 'clearTimeout').mockImplementation((id) => {
|
|
40
|
+
timeouts = timeouts.filter((timeout) => timeout.id !== id);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
(0, bun_test_1.afterEach)(() => {
|
|
44
|
+
bun_test_1.mock.restore();
|
|
45
|
+
});
|
|
46
|
+
const advanceTime = (ms) => {
|
|
47
|
+
currentTime += ms;
|
|
48
|
+
// Execute any timeouts that should have fired
|
|
49
|
+
const toExecute = timeouts.filter((timeout) => timeout.scheduledTime <= currentTime);
|
|
50
|
+
timeouts = timeouts.filter((timeout) => timeout.scheduledTime > currentTime);
|
|
51
|
+
toExecute.forEach((timeout) => timeout.callback());
|
|
52
|
+
};
|
|
53
|
+
(0, bun_test_1.describe)('createCountDetector', () => {
|
|
54
|
+
(0, bun_test_1.test)('should fire when threshold of repeated keys is met within time window', () => {
|
|
55
|
+
const detector = (0, rage_detector_1.createCountDetector)({
|
|
56
|
+
reason: 'key_mashing',
|
|
57
|
+
mode: 'COUNT',
|
|
58
|
+
threshold: 3,
|
|
59
|
+
timeWindow: 1000,
|
|
60
|
+
historyLimit: 10,
|
|
61
|
+
});
|
|
62
|
+
// Record 3 consecutive 'd' key presses
|
|
63
|
+
detector.recordEvent('d');
|
|
64
|
+
detector.recordEvent('d');
|
|
65
|
+
detector.recordEvent('d');
|
|
66
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
67
|
+
reason: 'key_mashing',
|
|
68
|
+
count: 3,
|
|
69
|
+
timeWindow: 1000,
|
|
70
|
+
repeatedKey: 'd',
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
(0, bun_test_1.test)('should NOT fire when keys are different', () => {
|
|
74
|
+
const detector = (0, rage_detector_1.createCountDetector)({
|
|
75
|
+
reason: 'key_mashing',
|
|
76
|
+
mode: 'COUNT',
|
|
77
|
+
threshold: 3,
|
|
78
|
+
timeWindow: 1000,
|
|
79
|
+
historyLimit: 10,
|
|
80
|
+
});
|
|
81
|
+
// Record different keys
|
|
82
|
+
detector.recordEvent('a');
|
|
83
|
+
detector.recordEvent('b');
|
|
84
|
+
detector.recordEvent('c');
|
|
85
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
(0, bun_test_1.test)('should NOT fire when threshold is not met', () => {
|
|
88
|
+
const detector = (0, rage_detector_1.createCountDetector)({
|
|
89
|
+
reason: 'key_mashing',
|
|
90
|
+
mode: 'COUNT',
|
|
91
|
+
threshold: 5,
|
|
92
|
+
timeWindow: 1000,
|
|
93
|
+
historyLimit: 10,
|
|
94
|
+
});
|
|
95
|
+
// Record only 2 repeated keys (below threshold of 5)
|
|
96
|
+
detector.recordEvent('d');
|
|
97
|
+
detector.recordEvent('d');
|
|
98
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
(0, bun_test_1.test)('should NOT fire when events are outside time window', () => {
|
|
101
|
+
const detector = (0, rage_detector_1.createCountDetector)({
|
|
102
|
+
reason: 'key_mashing',
|
|
103
|
+
mode: 'COUNT',
|
|
104
|
+
threshold: 3,
|
|
105
|
+
timeWindow: 1000,
|
|
106
|
+
historyLimit: 10,
|
|
107
|
+
});
|
|
108
|
+
// Record first key
|
|
109
|
+
detector.recordEvent('d');
|
|
110
|
+
// Advance time beyond window
|
|
111
|
+
advanceTime(1500);
|
|
112
|
+
// Record more keys - should not count the first one
|
|
113
|
+
detector.recordEvent('d');
|
|
114
|
+
detector.recordEvent('d');
|
|
115
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
(0, bun_test_1.test)('should respect debounce period', () => {
|
|
118
|
+
const detector = (0, rage_detector_1.createCountDetector)({
|
|
119
|
+
reason: 'key_mashing',
|
|
120
|
+
mode: 'COUNT',
|
|
121
|
+
threshold: 3,
|
|
122
|
+
timeWindow: 1000,
|
|
123
|
+
historyLimit: 10,
|
|
124
|
+
debounceMs: 5000,
|
|
125
|
+
});
|
|
126
|
+
// First trigger
|
|
127
|
+
detector.recordEvent('d');
|
|
128
|
+
detector.recordEvent('d');
|
|
129
|
+
detector.recordEvent('d');
|
|
130
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledTimes(1);
|
|
131
|
+
mockTrackEvent.mockClear();
|
|
132
|
+
// Try to trigger again immediately - should be debounced
|
|
133
|
+
detector.recordEvent('d');
|
|
134
|
+
detector.recordEvent('d');
|
|
135
|
+
detector.recordEvent('d');
|
|
136
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
137
|
+
// Advance past debounce period
|
|
138
|
+
advanceTime(5000);
|
|
139
|
+
// Should be able to trigger again
|
|
140
|
+
detector.recordEvent('d');
|
|
141
|
+
detector.recordEvent('d');
|
|
142
|
+
detector.recordEvent('d');
|
|
143
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledTimes(1);
|
|
144
|
+
});
|
|
145
|
+
(0, bun_test_1.test)('should enforce history limit to prevent memory leaks', () => {
|
|
146
|
+
const detector = (0, rage_detector_1.createCountDetector)({
|
|
147
|
+
reason: 'key_mashing',
|
|
148
|
+
mode: 'COUNT',
|
|
149
|
+
threshold: 3,
|
|
150
|
+
timeWindow: 10000, // Long window to keep events
|
|
151
|
+
historyLimit: 5,
|
|
152
|
+
});
|
|
153
|
+
// Record more events than the history limit
|
|
154
|
+
for (let i = 0; i < 10; i++) {
|
|
155
|
+
detector.recordEvent(`key${i}`);
|
|
156
|
+
advanceTime(100);
|
|
157
|
+
}
|
|
158
|
+
// The detector should have trimmed old events
|
|
159
|
+
// We can't directly test the internal history, but we can test behavior
|
|
160
|
+
// Record 3 of the same key - should trigger since recent events are kept
|
|
161
|
+
detector.recordEvent('same');
|
|
162
|
+
detector.recordEvent('same');
|
|
163
|
+
detector.recordEvent('same');
|
|
164
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
165
|
+
reason: 'key_mashing',
|
|
166
|
+
count: 3,
|
|
167
|
+
timeWindow: 10000,
|
|
168
|
+
repeatedKey: 'same',
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
(0, bun_test_1.describe)('createTimeBetweenDetector', () => {
|
|
173
|
+
(0, bun_test_1.test)('should fire when end() is called within threshold (default lt)', () => {
|
|
174
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
175
|
+
reason: 'quick_cancel',
|
|
176
|
+
mode: 'TIME_BETWEEN',
|
|
177
|
+
threshold: 3000,
|
|
178
|
+
operator: 'lt',
|
|
179
|
+
});
|
|
180
|
+
detector.start();
|
|
181
|
+
advanceTime(2000); // 2 seconds < 3 second threshold
|
|
182
|
+
detector.end();
|
|
183
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
184
|
+
reason: 'quick_cancel',
|
|
185
|
+
duration: 2000,
|
|
186
|
+
threshold: 3000,
|
|
187
|
+
operator: 'lt',
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
(0, bun_test_1.test)('should fire when end() is called within threshold (explicit lt)', () => {
|
|
191
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
192
|
+
reason: 'quick_cancel',
|
|
193
|
+
mode: 'TIME_BETWEEN',
|
|
194
|
+
threshold: 3000,
|
|
195
|
+
operator: 'lt',
|
|
196
|
+
});
|
|
197
|
+
detector.start();
|
|
198
|
+
advanceTime(2000); // 2 seconds < 3 second threshold
|
|
199
|
+
detector.end();
|
|
200
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
201
|
+
reason: 'quick_cancel',
|
|
202
|
+
duration: 2000,
|
|
203
|
+
threshold: 3000,
|
|
204
|
+
operator: 'lt',
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
(0, bun_test_1.test)('should fire when end() is called after threshold (gt)', () => {
|
|
208
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
209
|
+
reason: 'slow_operation',
|
|
210
|
+
mode: 'TIME_BETWEEN',
|
|
211
|
+
threshold: 3000,
|
|
212
|
+
operator: 'gt',
|
|
213
|
+
});
|
|
214
|
+
detector.start();
|
|
215
|
+
advanceTime(4000); // 4 seconds > 3 second threshold
|
|
216
|
+
detector.end();
|
|
217
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
218
|
+
reason: 'slow_operation',
|
|
219
|
+
duration: 4000,
|
|
220
|
+
threshold: 3000,
|
|
221
|
+
operator: 'gt',
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
(0, bun_test_1.test)('should fire when end() is called exactly at threshold (eq)', () => {
|
|
225
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
226
|
+
reason: 'exact_timing',
|
|
227
|
+
mode: 'TIME_BETWEEN',
|
|
228
|
+
threshold: 3000,
|
|
229
|
+
operator: 'eq',
|
|
230
|
+
});
|
|
231
|
+
detector.start();
|
|
232
|
+
advanceTime(3000); // exactly 3 seconds
|
|
233
|
+
detector.end();
|
|
234
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
235
|
+
reason: 'exact_timing',
|
|
236
|
+
duration: 3000,
|
|
237
|
+
threshold: 3000,
|
|
238
|
+
operator: 'eq',
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
(0, bun_test_1.test)('should fire when end() is called at or after threshold (gte)', () => {
|
|
242
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
243
|
+
reason: 'slow_or_exact',
|
|
244
|
+
mode: 'TIME_BETWEEN',
|
|
245
|
+
threshold: 3000,
|
|
246
|
+
operator: 'gte',
|
|
247
|
+
});
|
|
248
|
+
detector.start();
|
|
249
|
+
advanceTime(3000); // exactly 3 seconds
|
|
250
|
+
detector.end();
|
|
251
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
252
|
+
reason: 'slow_or_exact',
|
|
253
|
+
duration: 3000,
|
|
254
|
+
threshold: 3000,
|
|
255
|
+
operator: 'gte',
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
(0, bun_test_1.test)('should fire when end() is called at or before threshold (lte)', () => {
|
|
259
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
260
|
+
reason: 'quick_or_exact',
|
|
261
|
+
mode: 'TIME_BETWEEN',
|
|
262
|
+
threshold: 3000,
|
|
263
|
+
operator: 'lte',
|
|
264
|
+
});
|
|
265
|
+
detector.start();
|
|
266
|
+
advanceTime(3000); // exactly 3 seconds
|
|
267
|
+
detector.end();
|
|
268
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, {
|
|
269
|
+
reason: 'quick_or_exact',
|
|
270
|
+
duration: 3000,
|
|
271
|
+
threshold: 3000,
|
|
272
|
+
operator: 'lte',
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
(0, bun_test_1.test)('should NOT fire when end() is called after threshold (default lt)', () => {
|
|
276
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
277
|
+
reason: 'quick_cancel',
|
|
278
|
+
mode: 'TIME_BETWEEN',
|
|
279
|
+
threshold: 3000,
|
|
280
|
+
operator: 'lt'
|
|
281
|
+
});
|
|
282
|
+
detector.start();
|
|
283
|
+
advanceTime(4000); // 4 seconds > 3 second threshold
|
|
284
|
+
detector.end();
|
|
285
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
286
|
+
});
|
|
287
|
+
(0, bun_test_1.test)('should NOT fire when end() is called before threshold (gt)', () => {
|
|
288
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
289
|
+
reason: 'slow_operation',
|
|
290
|
+
mode: 'TIME_BETWEEN',
|
|
291
|
+
threshold: 3000,
|
|
292
|
+
operator: 'gt',
|
|
293
|
+
});
|
|
294
|
+
detector.start();
|
|
295
|
+
advanceTime(2000); // 2 seconds < 3 second threshold
|
|
296
|
+
detector.end();
|
|
297
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
298
|
+
});
|
|
299
|
+
(0, bun_test_1.test)('should NOT fire when end() is called without start()', () => {
|
|
300
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
301
|
+
reason: 'quick_cancel',
|
|
302
|
+
mode: 'TIME_BETWEEN',
|
|
303
|
+
threshold: 3000,
|
|
304
|
+
operator: 'lt'
|
|
305
|
+
});
|
|
306
|
+
detector.end();
|
|
307
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
308
|
+
});
|
|
309
|
+
(0, bun_test_1.test)('should respect cooldown period', () => {
|
|
310
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
311
|
+
reason: 'quick_cancel',
|
|
312
|
+
mode: 'TIME_BETWEEN',
|
|
313
|
+
threshold: 3000,
|
|
314
|
+
debounceMs: 10000,
|
|
315
|
+
operator: 'lt'
|
|
316
|
+
});
|
|
317
|
+
// First trigger
|
|
318
|
+
detector.start();
|
|
319
|
+
advanceTime(2000);
|
|
320
|
+
detector.end();
|
|
321
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledTimes(1);
|
|
322
|
+
mockTrackEvent.mockClear();
|
|
323
|
+
// Try to trigger again immediately - should be in cooldown
|
|
324
|
+
detector.start();
|
|
325
|
+
advanceTime(2000);
|
|
326
|
+
detector.end();
|
|
327
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
328
|
+
// Advance past cooldown period
|
|
329
|
+
advanceTime(10000);
|
|
330
|
+
// Should be able to trigger again
|
|
331
|
+
detector.start();
|
|
332
|
+
advanceTime(2000);
|
|
333
|
+
detector.end();
|
|
334
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledTimes(1);
|
|
335
|
+
});
|
|
336
|
+
(0, bun_test_1.test)('should handle multiple end() calls without start()', () => {
|
|
337
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
338
|
+
reason: 'multiple_ends',
|
|
339
|
+
mode: 'TIME_BETWEEN',
|
|
340
|
+
threshold: 3000,
|
|
341
|
+
operator: 'lt',
|
|
342
|
+
});
|
|
343
|
+
// Call end() multiple times without start()
|
|
344
|
+
detector.end();
|
|
345
|
+
detector.end();
|
|
346
|
+
detector.end();
|
|
347
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
348
|
+
});
|
|
349
|
+
(0, bun_test_1.test)('should handle multiple end() calls after single start()', () => {
|
|
350
|
+
const detector = (0, rage_detector_1.createTimeBetweenDetector)({
|
|
351
|
+
reason: 'multiple_ends',
|
|
352
|
+
mode: 'TIME_BETWEEN',
|
|
353
|
+
threshold: 3000,
|
|
354
|
+
operator: 'lt',
|
|
355
|
+
});
|
|
356
|
+
detector.start();
|
|
357
|
+
advanceTime(2000);
|
|
358
|
+
// First end() should trigger
|
|
359
|
+
detector.end();
|
|
360
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledTimes(1);
|
|
361
|
+
mockTrackEvent.mockClear();
|
|
362
|
+
// Subsequent end() calls should not trigger
|
|
363
|
+
detector.end();
|
|
364
|
+
detector.end();
|
|
365
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
(0, bun_test_1.describe)('createTimeoutDetector', () => {
|
|
369
|
+
(0, bun_test_1.test)('should fire when stop() is not called within timeout', () => {
|
|
370
|
+
const detector = (0, rage_detector_1.createTimeoutDetector)({
|
|
371
|
+
reason: 'websocket_hang',
|
|
372
|
+
timeoutMs: 60000,
|
|
373
|
+
});
|
|
374
|
+
detector.start({ context: 'test' });
|
|
375
|
+
advanceTime(60000); // Advance to timeout
|
|
376
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, bun_test_1.expect.objectContaining({
|
|
377
|
+
reason: 'websocket_hang',
|
|
378
|
+
durationMs: 60000,
|
|
379
|
+
timeoutMs: 60000,
|
|
380
|
+
context: 'test',
|
|
381
|
+
}));
|
|
382
|
+
});
|
|
383
|
+
(0, bun_test_1.test)('should NOT fire when stop() is called before timeout', () => {
|
|
384
|
+
const detector = (0, rage_detector_1.createTimeoutDetector)({
|
|
385
|
+
reason: 'websocket_hang',
|
|
386
|
+
timeoutMs: 60000,
|
|
387
|
+
});
|
|
388
|
+
detector.start();
|
|
389
|
+
advanceTime(30000); // Advance halfway
|
|
390
|
+
detector.stop();
|
|
391
|
+
advanceTime(60000); // Advance past original timeout
|
|
392
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
393
|
+
});
|
|
394
|
+
(0, bun_test_1.test)('should call onHang callback when timeout occurs', () => {
|
|
395
|
+
const onHangCallback = (0, bun_test_1.mock)(() => { });
|
|
396
|
+
const detector = (0, rage_detector_1.createTimeoutDetector)({
|
|
397
|
+
reason: 'websocket_hang',
|
|
398
|
+
timeoutMs: 60000,
|
|
399
|
+
onHang: onHangCallback,
|
|
400
|
+
});
|
|
401
|
+
detector.start();
|
|
402
|
+
advanceTime(60000);
|
|
403
|
+
(0, bun_test_1.expect)(onHangCallback).toHaveBeenCalledTimes(1);
|
|
404
|
+
});
|
|
405
|
+
(0, bun_test_1.test)('should clear previous timeout when start() is called again', () => {
|
|
406
|
+
const detector = (0, rage_detector_1.createTimeoutDetector)({
|
|
407
|
+
reason: 'websocket_hang',
|
|
408
|
+
timeoutMs: 60000,
|
|
409
|
+
});
|
|
410
|
+
detector.start();
|
|
411
|
+
advanceTime(30000);
|
|
412
|
+
// Start again - should clear previous timeout
|
|
413
|
+
detector.start();
|
|
414
|
+
advanceTime(30000); // Total 60s from first start, but only 30s from second
|
|
415
|
+
(0, bun_test_1.expect)(mockTrackEvent).not.toHaveBeenCalled();
|
|
416
|
+
// Advance another 30s to trigger the second timeout
|
|
417
|
+
advanceTime(30000);
|
|
418
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledTimes(1);
|
|
419
|
+
});
|
|
420
|
+
(0, bun_test_1.test)('should merge context from options and start() call', () => {
|
|
421
|
+
const detector = (0, rage_detector_1.createTimeoutDetector)({
|
|
422
|
+
reason: 'context_test',
|
|
423
|
+
timeoutMs: 60000,
|
|
424
|
+
context: { globalContext: 'global' },
|
|
425
|
+
});
|
|
426
|
+
detector.start({ localContext: 'local', overrideGlobal: 'fromLocal' });
|
|
427
|
+
advanceTime(60000);
|
|
428
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, bun_test_1.expect.objectContaining({
|
|
429
|
+
reason: 'context_test',
|
|
430
|
+
globalContext: 'global',
|
|
431
|
+
localContext: 'local',
|
|
432
|
+
overrideGlobal: 'fromLocal',
|
|
433
|
+
}));
|
|
434
|
+
});
|
|
435
|
+
(0, bun_test_1.test)('should handle start() with no context when options context exists', () => {
|
|
436
|
+
const detector = (0, rage_detector_1.createTimeoutDetector)({
|
|
437
|
+
reason: 'context_test',
|
|
438
|
+
timeoutMs: 60000,
|
|
439
|
+
context: { globalOnly: 'global' },
|
|
440
|
+
});
|
|
441
|
+
detector.start();
|
|
442
|
+
advanceTime(60000);
|
|
443
|
+
(0, bun_test_1.expect)(mockTrackEvent).toHaveBeenCalledWith(analytics_events_1.AnalyticsEvent.RAGE, bun_test_1.expect.objectContaining({
|
|
444
|
+
reason: 'context_test',
|
|
445
|
+
globalOnly: 'global',
|
|
446
|
+
}));
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
//# sourceMappingURL=rage-detector.test.js.map
|