Set up comprehensive frontend testing infrastructure
- Install Jest for unit testing with React Testing Library - Install Playwright for end-to-end testing - Configure Jest with proper TypeScript support and module mapping - Create test setup files and utilities for both unit and e2e tests Components: * Jest configuration with coverage thresholds * Playwright configuration with browser automation * Unit tests for LoginForm, AuthContext, and useSocketIO hook * E2E tests for authentication, dashboard, and agents workflows * GitHub Actions workflow for automated testing * Mock data and API utilities for consistent testing * Test documentation with best practices Testing features: - Unit tests with 70% coverage threshold - E2E tests with API mocking and user journey testing - CI/CD integration for automated test runs - Cross-browser testing support with Playwright - Authentication system testing end-to-end 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										115
									
								
								frontend/node_modules/execa/lib/kill.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								frontend/node_modules/execa/lib/kill.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| 'use strict'; | ||||
| const os = require('os'); | ||||
| const onExit = require('signal-exit'); | ||||
|  | ||||
| const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5; | ||||
|  | ||||
| // Monkey-patches `childProcess.kill()` to add `forceKillAfterTimeout` behavior | ||||
| const spawnedKill = (kill, signal = 'SIGTERM', options = {}) => { | ||||
| 	const killResult = kill(signal); | ||||
| 	setKillTimeout(kill, signal, options, killResult); | ||||
| 	return killResult; | ||||
| }; | ||||
|  | ||||
| const setKillTimeout = (kill, signal, options, killResult) => { | ||||
| 	if (!shouldForceKill(signal, options, killResult)) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	const timeout = getForceKillAfterTimeout(options); | ||||
| 	const t = setTimeout(() => { | ||||
| 		kill('SIGKILL'); | ||||
| 	}, timeout); | ||||
|  | ||||
| 	// Guarded because there's no `.unref()` when `execa` is used in the renderer | ||||
| 	// process in Electron. This cannot be tested since we don't run tests in | ||||
| 	// Electron. | ||||
| 	// istanbul ignore else | ||||
| 	if (t.unref) { | ||||
| 		t.unref(); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| const shouldForceKill = (signal, {forceKillAfterTimeout}, killResult) => { | ||||
| 	return isSigterm(signal) && forceKillAfterTimeout !== false && killResult; | ||||
| }; | ||||
|  | ||||
| const isSigterm = signal => { | ||||
| 	return signal === os.constants.signals.SIGTERM || | ||||
| 		(typeof signal === 'string' && signal.toUpperCase() === 'SIGTERM'); | ||||
| }; | ||||
|  | ||||
| const getForceKillAfterTimeout = ({forceKillAfterTimeout = true}) => { | ||||
| 	if (forceKillAfterTimeout === true) { | ||||
| 		return DEFAULT_FORCE_KILL_TIMEOUT; | ||||
| 	} | ||||
|  | ||||
| 	if (!Number.isFinite(forceKillAfterTimeout) || forceKillAfterTimeout < 0) { | ||||
| 		throw new TypeError(`Expected the \`forceKillAfterTimeout\` option to be a non-negative integer, got \`${forceKillAfterTimeout}\` (${typeof forceKillAfterTimeout})`); | ||||
| 	} | ||||
|  | ||||
| 	return forceKillAfterTimeout; | ||||
| }; | ||||
|  | ||||
| // `childProcess.cancel()` | ||||
| const spawnedCancel = (spawned, context) => { | ||||
| 	const killResult = spawned.kill(); | ||||
|  | ||||
| 	if (killResult) { | ||||
| 		context.isCanceled = true; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| const timeoutKill = (spawned, signal, reject) => { | ||||
| 	spawned.kill(signal); | ||||
| 	reject(Object.assign(new Error('Timed out'), {timedOut: true, signal})); | ||||
| }; | ||||
|  | ||||
| // `timeout` option handling | ||||
| const setupTimeout = (spawned, {timeout, killSignal = 'SIGTERM'}, spawnedPromise) => { | ||||
| 	if (timeout === 0 || timeout === undefined) { | ||||
| 		return spawnedPromise; | ||||
| 	} | ||||
|  | ||||
| 	let timeoutId; | ||||
| 	const timeoutPromise = new Promise((resolve, reject) => { | ||||
| 		timeoutId = setTimeout(() => { | ||||
| 			timeoutKill(spawned, killSignal, reject); | ||||
| 		}, timeout); | ||||
| 	}); | ||||
|  | ||||
| 	const safeSpawnedPromise = spawnedPromise.finally(() => { | ||||
| 		clearTimeout(timeoutId); | ||||
| 	}); | ||||
|  | ||||
| 	return Promise.race([timeoutPromise, safeSpawnedPromise]); | ||||
| }; | ||||
|  | ||||
| const validateTimeout = ({timeout}) => { | ||||
| 	if (timeout !== undefined && (!Number.isFinite(timeout) || timeout < 0)) { | ||||
| 		throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| // `cleanup` option handling | ||||
| const setExitHandler = async (spawned, {cleanup, detached}, timedPromise) => { | ||||
| 	if (!cleanup || detached) { | ||||
| 		return timedPromise; | ||||
| 	} | ||||
|  | ||||
| 	const removeExitHandler = onExit(() => { | ||||
| 		spawned.kill(); | ||||
| 	}); | ||||
|  | ||||
| 	return timedPromise.finally(() => { | ||||
| 		removeExitHandler(); | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
| 	spawnedKill, | ||||
| 	spawnedCancel, | ||||
| 	setupTimeout, | ||||
| 	validateTimeout, | ||||
| 	setExitHandler | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user
	 anthonyrawlins
					anthonyrawlins