browser-commander 0.2.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/CHANGELOG.md +28 -0
- package/package.json +1 -1
- package/src/core/navigation-safety.js +29 -0
- package/src/exports.js +1 -0
- package/tests/unit/core/navigation-safety.test.js +75 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 03e9ccb: Add isTimeoutError function for detecting timeout errors
|
|
8
|
+
|
|
9
|
+
Adds a new `isTimeoutError` function exported from the library that helps detect timeout errors from selector waiting operations. This function is complementary to `isNavigationError` and allows automation loops to handle timeout errors gracefully without crashing.
|
|
10
|
+
|
|
11
|
+
Usage example:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { isTimeoutError } from 'browser-commander';
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
await page.waitForSelector('.button');
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (isTimeoutError(error)) {
|
|
20
|
+
console.log('Timeout occurred, continuing with next item...');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 0.2.1
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Test patch release
|
|
30
|
+
|
|
3
31
|
## 0.2.0
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -158,3 +158,32 @@ export function withNavigationSafety(fn, options = {}) {
|
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if an error is a timeout error from selector waiting
|
|
164
|
+
* These errors should be treated as non-fatal in automation loops
|
|
165
|
+
* @param {Error} error - The error to check
|
|
166
|
+
* @returns {boolean} - True if this is a timeout error
|
|
167
|
+
*/
|
|
168
|
+
export function isTimeoutError(error) {
|
|
169
|
+
if (!error) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Check error name first (most reliable)
|
|
174
|
+
if (error.name === 'TimeoutError') {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check error message patterns (case-insensitive)
|
|
179
|
+
const message = (error.message || '').toLowerCase();
|
|
180
|
+
const timeoutErrorPatterns = [
|
|
181
|
+
'waiting for selector',
|
|
182
|
+
'timeout',
|
|
183
|
+
'timeouterror',
|
|
184
|
+
'timeout exceeded',
|
|
185
|
+
'timed out',
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
return timeoutErrorPatterns.some((pattern) => message.includes(pattern));
|
|
189
|
+
}
|
package/src/exports.js
CHANGED
|
@@ -2,6 +2,7 @@ import { describe, it } from 'node:test';
|
|
|
2
2
|
import assert from 'node:assert';
|
|
3
3
|
import {
|
|
4
4
|
isNavigationError,
|
|
5
|
+
isTimeoutError,
|
|
5
6
|
safeOperation,
|
|
6
7
|
makeNavigationSafe,
|
|
7
8
|
withNavigationSafety,
|
|
@@ -67,6 +68,80 @@ describe('navigation-safety', () => {
|
|
|
67
68
|
});
|
|
68
69
|
});
|
|
69
70
|
|
|
71
|
+
describe('isTimeoutError', () => {
|
|
72
|
+
it('should return false for null', () => {
|
|
73
|
+
assert.strictEqual(isTimeoutError(null), false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should return false for undefined', () => {
|
|
77
|
+
assert.strictEqual(isTimeoutError(undefined), false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should return false for error without message or name', () => {
|
|
81
|
+
assert.strictEqual(isTimeoutError({}), false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return false for regular error', () => {
|
|
85
|
+
const error = new Error('Some regular error');
|
|
86
|
+
assert.strictEqual(isTimeoutError(error), false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should return true for error with name "TimeoutError"', () => {
|
|
90
|
+
const error = new Error('Something failed');
|
|
91
|
+
error.name = 'TimeoutError';
|
|
92
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should return true for "waiting for selector" error', () => {
|
|
96
|
+
const error = new Error('Waiting for selector ".button" timed out');
|
|
97
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should return true for "timeout" error (case-insensitive)', () => {
|
|
101
|
+
const error = new Error('Timeout while waiting for element');
|
|
102
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should return true for "timeout exceeded" error', () => {
|
|
106
|
+
const error = new Error('timeout exceeded');
|
|
107
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should return true for "timed out" error', () => {
|
|
111
|
+
const error = new Error('Operation timed out after 30000ms');
|
|
112
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should return true for Playwright locator timeout error', () => {
|
|
116
|
+
const error = new Error(
|
|
117
|
+
'locator.click: Timeout 30000ms exceeded. Waiting for selector "button.submit"'
|
|
118
|
+
);
|
|
119
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should return true for Puppeteer waitForSelector timeout', () => {
|
|
123
|
+
const error = new Error(
|
|
124
|
+
'waiting for selector `#myElement` failed: timeout 30000ms exceeded'
|
|
125
|
+
);
|
|
126
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should handle uppercase TIMEOUT in message', () => {
|
|
130
|
+
const error = new Error('TIMEOUT ERROR occurred');
|
|
131
|
+
assert.strictEqual(isTimeoutError(error), true);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should not match navigation errors as timeout errors', () => {
|
|
135
|
+
const error = new Error('Execution context was destroyed');
|
|
136
|
+
assert.strictEqual(isTimeoutError(error), false);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should not match frame detached errors as timeout errors', () => {
|
|
140
|
+
const error = new Error('frame was detached');
|
|
141
|
+
assert.strictEqual(isTimeoutError(error), false);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
70
145
|
describe('safeOperation', () => {
|
|
71
146
|
it('should return success result on successful operation', async () => {
|
|
72
147
|
const result = await safeOperation(async () => 'success');
|