您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

network-error-monitor.md 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. # Network Error Monitor
  2. ## Principle
  3. Automatically detect and fail tests when HTTP 4xx/5xx errors occur during execution. Act like Sentry for tests - catch silent backend failures even when UI passes assertions.
  4. ## Rationale
  5. Traditional Playwright tests focus on UI:
  6. - Backend 500 errors ignored if UI looks correct
  7. - Silent failures slip through
  8. - No visibility into background API health
  9. - Tests pass while features are broken
  10. The `network-error-monitor` provides:
  11. - **Automatic detection**: All HTTP 4xx/5xx responses tracked
  12. - **Test failures**: Fail tests with backend errors (even if UI passes)
  13. - **Structured artifacts**: JSON reports with error details
  14. - **Smart opt-out**: Disable for validation tests expecting errors
  15. - **Deduplication**: Group repeated errors by pattern
  16. - **Domino effect prevention**: Limit test failures per error pattern
  17. - **Respects test status**: Won't suppress actual test failures
  18. ## Quick Start
  19. ```typescript
  20. import { test } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  21. // That's it! Network monitoring is automatically enabled
  22. test('my test', async ({ page }) => {
  23. await page.goto('/dashboard');
  24. // If any HTTP 4xx/5xx errors occur, the test will fail
  25. });
  26. ```
  27. ## Pattern Examples
  28. ### Example 1: Basic Auto-Monitoring
  29. **Context**: Automatically fail tests when backend errors occur.
  30. **Implementation**:
  31. ```typescript
  32. import { test } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  33. // Monitoring automatically enabled
  34. test('should load dashboard', async ({ page }) => {
  35. await page.goto('/dashboard');
  36. await expect(page.locator('h1')).toContainText('Dashboard');
  37. // Passes if no HTTP errors
  38. // Fails if any 4xx/5xx errors detected with clear message:
  39. // "Network errors detected: 2 request(s) failed"
  40. // Failed requests:
  41. // GET 500 https://api.example.com/users
  42. // POST 503 https://api.example.com/metrics
  43. });
  44. ```
  45. **Key Points**:
  46. - Zero setup - auto-enabled for all tests
  47. - Fails on any 4xx/5xx response
  48. - Structured error message with URLs and status codes
  49. - JSON artifact attached to test report
  50. ### Example 2: Opt-Out for Validation Tests
  51. **Context**: Some tests expect errors (validation, error handling, edge cases).
  52. **Implementation**:
  53. ```typescript
  54. import { test } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  55. // Opt-out with annotation
  56. test('should show error on invalid input', { annotation: [{ type: 'skipNetworkMonitoring' }] }, async ({ page }) => {
  57. await page.goto('/form');
  58. await page.click('#submit'); // Triggers 400 error
  59. // Monitoring disabled - test won't fail on 400
  60. await expect(page.getByText('Invalid input')).toBeVisible();
  61. });
  62. // Or opt-out entire describe block
  63. test.describe('error handling', { annotation: [{ type: 'skipNetworkMonitoring' }] }, () => {
  64. test('handles 404', async ({ page }) => {
  65. // All tests in this block skip monitoring
  66. });
  67. test('handles 500', async ({ page }) => {
  68. // Monitoring disabled
  69. });
  70. });
  71. ```
  72. **Key Points**:
  73. - Use annotation `{ type: 'skipNetworkMonitoring' }`
  74. - Can opt-out single test or entire describe block
  75. - Monitoring still active for other tests
  76. - Perfect for intentional error scenarios
  77. ### Example 3: Respects Test Status
  78. **Context**: The monitor respects final test statuses to avoid suppressing important test outcomes.
  79. **Behavior by test status:**
  80. - **`failed`**: Network errors logged as additional context, not thrown
  81. - **`timedOut`**: Network errors logged as additional context
  82. - **`skipped`**: Network errors logged, skip status preserved
  83. - **`interrupted`**: Network errors logged, interrupted status preserved
  84. - **`passed`**: Network errors throw and fail the test
  85. **Example with test.skip():**
  86. ```typescript
  87. test('feature gated test', async ({ page }) => {
  88. const featureEnabled = await checkFeatureFlag();
  89. test.skip(!featureEnabled, 'Feature not enabled');
  90. // If skipped, network errors won't turn this into a failure
  91. await page.goto('/new-feature');
  92. });
  93. ```
  94. ### Example 4: Excluding Legitimate Errors
  95. **Context**: Some endpoints legitimately return 4xx/5xx responses.
  96. **Implementation**:
  97. ```typescript
  98. import { test as base } from '@playwright/test';
  99. import { createNetworkErrorMonitorFixture } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  100. export const test = base.extend(
  101. createNetworkErrorMonitorFixture({
  102. excludePatterns: [
  103. /email-cluster\/ml-app\/has-active-run/, // ML service returns 404 when no active run
  104. /idv\/session-templates\/list/, // IDV service returns 404 when not configured
  105. /sentry\.io\/api/, // External Sentry errors should not fail tests
  106. ],
  107. }),
  108. );
  109. ```
  110. **For merged fixtures:**
  111. ```typescript
  112. import { test as base, mergeTests } from '@playwright/test';
  113. import { createNetworkErrorMonitorFixture } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  114. const networkErrorMonitor = base.extend(
  115. createNetworkErrorMonitorFixture({
  116. excludePatterns: [/analytics\.google\.com/, /cdn\.example\.com/],
  117. }),
  118. );
  119. export const test = mergeTests(authFixture, networkErrorMonitor);
  120. ```
  121. ### Example 5: Preventing Domino Effect
  122. **Context**: One failing endpoint shouldn't fail all tests.
  123. **Implementation**:
  124. ```typescript
  125. import { test as base } from '@playwright/test';
  126. import { createNetworkErrorMonitorFixture } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  127. const networkErrorMonitor = base.extend(
  128. createNetworkErrorMonitorFixture({
  129. excludePatterns: [], // Required when using maxTestsPerError
  130. maxTestsPerError: 1, // Only first test fails per error pattern, rest just log
  131. }),
  132. );
  133. ```
  134. **How it works:**
  135. When `/api/v2/case-management/cases` returns 500:
  136. - **First test** encountering this error: **FAILS** with clear error message
  137. - **Subsequent tests** encountering same error: **PASSES** but logs warning
  138. Error patterns are grouped by `method + status + base path`:
  139. - `GET /api/v2/case-management/cases/123` -> Pattern: `GET:500:/api/v2/case-management`
  140. - `GET /api/v2/case-management/quota` -> Pattern: `GET:500:/api/v2/case-management` (same group!)
  141. - `POST /api/v2/case-management/cases` -> Pattern: `POST:500:/api/v2/case-management` (different group!)
  142. **Why include HTTP method?** A GET 404 vs POST 404 might represent different issues:
  143. - `GET 404 /api/users/123` -> User not found (expected in some tests)
  144. - `POST 404 /api/users` -> Endpoint doesn't exist (critical error)
  145. **Output for subsequent tests:**
  146. ```
  147. Warning: Network errors detected but not failing test (maxTestsPerError limit reached):
  148. GET 500 https://api.example.com/api/v2/case-management/cases
  149. ```
  150. **Recommended configuration:**
  151. ```typescript
  152. createNetworkErrorMonitorFixture({
  153. excludePatterns: [...], // Required - known broken endpoints (can be empty [])
  154. maxTestsPerError: 1 // Stop domino effect (requires excludePatterns)
  155. })
  156. ```
  157. **Understanding worker-level state:**
  158. Error pattern counts are stored in worker-level global state:
  159. ```typescript
  160. // test-file-1.spec.ts (runs in Worker 1)
  161. test('test A', () => {
  162. /* triggers GET:500:/api/v2/cases */
  163. }); // FAILS
  164. // test-file-2.spec.ts (runs later in Worker 1)
  165. test('test B', () => {
  166. /* triggers GET:500:/api/v2/cases */
  167. }); // PASSES (limit reached)
  168. // test-file-3.spec.ts (runs in Worker 2 - different worker)
  169. test('test C', () => {
  170. /* triggers GET:500:/api/v2/cases */
  171. }); // FAILS (fresh worker)
  172. ```
  173. ### Example 6: Integration with Merged Fixtures
  174. **Context**: Combine network-error-monitor with other utilities.
  175. **Implementation**:
  176. ```typescript
  177. // playwright/support/merged-fixtures.ts
  178. import { mergeTests } from '@playwright/test';
  179. import { test as authFixture } from '@seontechnologies/playwright-utils/auth-session/fixtures';
  180. import { test as networkErrorMonitorFixture } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  181. export const test = mergeTests(
  182. authFixture,
  183. networkErrorMonitorFixture,
  184. // Add other fixtures
  185. );
  186. // In tests
  187. import { test, expect } from '../support/merged-fixtures';
  188. test('authenticated with monitoring', async ({ page, authToken }) => {
  189. // Both auth and network monitoring active
  190. await page.goto('/protected');
  191. // Fails if backend returns errors during auth flow
  192. });
  193. ```
  194. **Key Points**:
  195. - Combine with `mergeTests`
  196. - Works alongside all other utilities
  197. - Monitoring active automatically
  198. - No extra setup needed
  199. ### Example 7: Artifact Structure
  200. **Context**: Debugging failed tests with network error artifacts.
  201. When test fails due to network errors, artifact attached:
  202. ```json
  203. [
  204. {
  205. "url": "https://api.example.com/users",
  206. "status": 500,
  207. "method": "GET",
  208. "timestamp": "2025-11-10T12:34:56.789Z"
  209. },
  210. {
  211. "url": "https://api.example.com/metrics",
  212. "status": 503,
  213. "method": "POST",
  214. "timestamp": "2025-11-10T12:34:57.123Z"
  215. }
  216. ]
  217. ```
  218. ## Implementation Details
  219. ### How It Works
  220. 1. **Fixture Extension**: Uses Playwright's `base.extend()` with `auto: true`
  221. 2. **Response Listener**: Attaches `page.on('response')` listener at test start
  222. 3. **Multi-Page Monitoring**: Automatically monitors popups and new tabs via `context.on('page')`
  223. 4. **Error Collection**: Captures 4xx/5xx responses, checking exclusion patterns
  224. 5. **Try/Finally**: Ensures error processing runs even if test fails early
  225. 6. **Status Check**: Only throws errors if test hasn't already reached final status
  226. 7. **Artifact**: Attaches JSON file to test report for debugging
  227. ### Performance
  228. The monitor has minimal performance impact:
  229. - Event listener overhead: ~0.1ms per response
  230. - Memory: ~200 bytes per unique error
  231. - No network delay (observes responses, doesn't intercept them)
  232. ## Comparison with Alternatives
  233. | Approach | Network Error Monitor | Manual afterEach |
  234. | --------------------------- | --------------------- | --------------------- |
  235. | **Setup Required** | Zero (auto-enabled) | Every test file |
  236. | **Catches Silent Failures** | Yes | Yes (if configured) |
  237. | **Structured Artifacts** | JSON attached | Custom impl |
  238. | **Test Failure Safety** | Try/finally | afterEach may not run |
  239. | **Opt-Out Mechanism** | Annotation | Custom logic |
  240. | **Status Aware** | Respects skip/failed | No |
  241. ## When to Use
  242. **Auto-enabled for:**
  243. - All E2E tests
  244. - Integration tests
  245. - Any test hitting real APIs
  246. **Opt-out for:**
  247. - Validation tests (expecting 4xx)
  248. - Error handling tests (expecting 5xx)
  249. - Offline tests (network-recorder playback)
  250. ## Troubleshooting
  251. ### Test fails with network errors but I don't see them in my app
  252. The errors might be happening during page load or in background polling. Check the `network-errors.json` artifact in your test report for full details including timestamps.
  253. ### False positives from external services
  254. Configure exclusion patterns as shown in the "Excluding Legitimate Errors" section above.
  255. ### Network errors not being caught
  256. Ensure you're importing the test from the correct fixture:
  257. ```typescript
  258. // Correct
  259. import { test } from '@seontechnologies/playwright-utils/network-error-monitor/fixtures';
  260. // Wrong - this won't have network monitoring
  261. import { test } from '@playwright/test';
  262. ```
  263. ## Related Fragments
  264. - `overview.md` - Installation and fixtures
  265. - `fixtures-composition.md` - Merging with other utilities
  266. - `error-handling.md` - Traditional error handling patterns
  267. ## Anti-Patterns
  268. **DON'T opt out of monitoring globally:**
  269. ```typescript
  270. // Every test skips monitoring
  271. test.use({ annotation: [{ type: 'skipNetworkMonitoring' }] });
  272. ```
  273. **DO opt-out only for specific error tests:**
  274. ```typescript
  275. test.describe('error scenarios', { annotation: [{ type: 'skipNetworkMonitoring' }] }, () => {
  276. // Only these tests skip monitoring
  277. });
  278. ```
  279. **DON'T ignore network error artifacts:**
  280. ```typescript
  281. // Test fails, artifact shows 500 errors
  282. // Developer: "Works on my machine" ¯\_(ツ)_/¯
  283. ```
  284. **DO check artifacts for root cause:**
  285. ```typescript
  286. // Read network-errors.json artifact
  287. // Identify failing endpoint: GET /api/users -> 500
  288. // Fix backend issue before merging
  289. ```