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:
		
							
								
								
									
										155
									
								
								frontend/node_modules/@testing-library/user-event/dist/esm/event/input.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								frontend/node_modules/@testing-library/user-event/dist/esm/event/input.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| import { setUIValue, clearInitialValue, getUIValue } from '../document/UI.js'; | ||||
| import { isElementType } from '../utils/misc/isElementType.js'; | ||||
| import '../utils/dataTransfer/Clipboard.js'; | ||||
| import { isValidDateOrTimeValue, buildTimeValue } from '../utils/edit/timeValue.js'; | ||||
| import { supportsMaxLength, getMaxLength } from '../utils/edit/maxLength.js'; | ||||
| import { getNextCursorPosition } from '../utils/focus/cursor.js'; | ||||
| import { commitValueAfterInput } from '../document/trackValue.js'; | ||||
| import { getInputRange } from './selection/getInputRange.js'; | ||||
| import { setSelection } from './selection/setSelection.js'; | ||||
|  | ||||
| function isDateOrTime(element) { | ||||
|     return isElementType(element, 'input') && [ | ||||
|         'date', | ||||
|         'time' | ||||
|     ].includes(element.type); | ||||
| } | ||||
| function input(instance, element, data, inputType = 'insertText') { | ||||
|     const inputRange = getInputRange(element); | ||||
|     /* istanbul ignore if */ if (!inputRange) { | ||||
|         return; | ||||
|     } | ||||
|     // There is no `beforeinput` event on `date` and `time` input | ||||
|     if (!isDateOrTime(element)) { | ||||
|         const unprevented = instance.dispatchUIEvent(element, 'beforeinput', { | ||||
|             inputType, | ||||
|             data | ||||
|         }); | ||||
|         if (!unprevented) { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     if ('startContainer' in inputRange) { | ||||
|         editContenteditable(instance, element, inputRange, data, inputType); | ||||
|     } else { | ||||
|         editInputElement(instance, element, inputRange, data, inputType); | ||||
|     } | ||||
| } | ||||
| function editContenteditable(instance, element, inputRange, data, inputType) { | ||||
|     let del = false; | ||||
|     if (!inputRange.collapsed) { | ||||
|         del = true; | ||||
|         inputRange.deleteContents(); | ||||
|     } else if ([ | ||||
|         'deleteContentBackward', | ||||
|         'deleteContentForward' | ||||
|     ].includes(inputType)) { | ||||
|         const nextPosition = getNextCursorPosition(inputRange.startContainer, inputRange.startOffset, inputType === 'deleteContentBackward' ? -1 : 1, inputType); | ||||
|         if (nextPosition) { | ||||
|             del = true; | ||||
|             const delRange = inputRange.cloneRange(); | ||||
|             if (delRange.comparePoint(nextPosition.node, nextPosition.offset) < 0) { | ||||
|                 delRange.setStart(nextPosition.node, nextPosition.offset); | ||||
|             } else { | ||||
|                 delRange.setEnd(nextPosition.node, nextPosition.offset); | ||||
|             } | ||||
|             delRange.deleteContents(); | ||||
|         } | ||||
|     } | ||||
|     if (data) { | ||||
|         if (inputRange.endContainer.nodeType === 3) { | ||||
|             const offset = inputRange.endOffset; | ||||
|             inputRange.endContainer.insertData(offset, data); | ||||
|             inputRange.setStart(inputRange.endContainer, offset + data.length); | ||||
|             inputRange.setEnd(inputRange.endContainer, offset + data.length); | ||||
|         } else { | ||||
|             const text = element.ownerDocument.createTextNode(data); | ||||
|             inputRange.insertNode(text); | ||||
|             inputRange.setStart(text, data.length); | ||||
|             inputRange.setEnd(text, data.length); | ||||
|         } | ||||
|     } | ||||
|     if (del || data) { | ||||
|         instance.dispatchUIEvent(element, 'input', { | ||||
|             inputType | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| function editInputElement(instance, element, inputRange, data, inputType) { | ||||
|     let dataToInsert = data; | ||||
|     if (supportsMaxLength(element)) { | ||||
|         const maxLength = getMaxLength(element); | ||||
|         if (maxLength !== undefined && data.length > 0) { | ||||
|             const spaceUntilMaxLength = maxLength - element.value.length; | ||||
|             if (spaceUntilMaxLength > 0) { | ||||
|                 dataToInsert = data.substring(0, spaceUntilMaxLength); | ||||
|             } else { | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     const { newValue, newOffset, oldValue } = calculateNewValue(dataToInsert, element, inputRange, inputType); | ||||
|     if (newValue === oldValue && newOffset === inputRange.startOffset && newOffset === inputRange.endOffset) { | ||||
|         return; | ||||
|     } | ||||
|     if (isElementType(element, 'input', { | ||||
|         type: 'number' | ||||
|     }) && !isValidNumberInput(newValue)) { | ||||
|         return; | ||||
|     } | ||||
|     setUIValue(element, newValue); | ||||
|     setSelection({ | ||||
|         focusNode: element, | ||||
|         anchorOffset: newOffset, | ||||
|         focusOffset: newOffset | ||||
|     }); | ||||
|     if (isDateOrTime(element)) { | ||||
|         if (isValidDateOrTimeValue(element, newValue)) { | ||||
|             commitInput(instance, element, newOffset, {}); | ||||
|             instance.dispatchUIEvent(element, 'change'); | ||||
|             clearInitialValue(element); | ||||
|         } | ||||
|     } else { | ||||
|         commitInput(instance, element, newOffset, { | ||||
|             data, | ||||
|             inputType | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| function calculateNewValue(inputData, node, { startOffset, endOffset }, inputType) { | ||||
|     const value = getUIValue(node); | ||||
|     const prologEnd = Math.max(0, startOffset === endOffset && inputType === 'deleteContentBackward' ? startOffset - 1 : startOffset); | ||||
|     const prolog = value.substring(0, prologEnd); | ||||
|     const epilogStart = Math.min(value.length, startOffset === endOffset && inputType === 'deleteContentForward' ? startOffset + 1 : endOffset); | ||||
|     const epilog = value.substring(epilogStart, value.length); | ||||
|     let newValue = `${prolog}${inputData}${epilog}`; | ||||
|     let newOffset = prologEnd + inputData.length; | ||||
|     if (isElementType(node, 'input', { | ||||
|         type: 'time' | ||||
|     })) { | ||||
|         const builtValue = buildTimeValue(newValue); | ||||
|         if (builtValue !== '' && isValidDateOrTimeValue(node, builtValue)) { | ||||
|             newValue = builtValue; | ||||
|             newOffset = builtValue.length; | ||||
|         } | ||||
|     } | ||||
|     return { | ||||
|         oldValue: value, | ||||
|         newValue, | ||||
|         newOffset | ||||
|     }; | ||||
| } | ||||
| function commitInput(instance, element, newOffset, inputInit) { | ||||
|     instance.dispatchUIEvent(element, 'input', inputInit); | ||||
|     commitValueAfterInput(element, newOffset); | ||||
| } | ||||
| function isValidNumberInput(value) { | ||||
|     var _value_match, _value_match1; | ||||
|     // the browser allows some invalid input but not others | ||||
|     // it allows up to two '-' at any place before any 'e' or one directly following 'e' | ||||
|     // it allows one '.' at any place before e | ||||
|     const valueParts = value.split('e', 2); | ||||
|     return !(/[^\d.\-e]/.test(value) || Number((_value_match = value.match(/-/g)) === null || _value_match === undefined ? undefined : _value_match.length) > 2 || Number((_value_match1 = value.match(/\./g)) === null || _value_match1 === undefined ? undefined : _value_match1.length) > 1 || valueParts[1] && !/^-?\d*$/.test(valueParts[1])); | ||||
| } | ||||
|  | ||||
| export { input }; | ||||
		Reference in New Issue
	
	Block a user
	 anthonyrawlins
					anthonyrawlins