 aacb45156b
			
		
	
	aacb45156b
	
	
	
		
			
			- 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>
		
			
				
	
	
		
			161 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  Copyright 2015, Yahoo Inc.
 | |
|  Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 | |
|  */
 | |
| 'use strict';
 | |
| 
 | |
| const debug = require('debug')('istanbuljs');
 | |
| const libCoverage = require('istanbul-lib-coverage');
 | |
| const { MappedCoverage } = require('./mapped');
 | |
| const getMapping = require('./get-mapping');
 | |
| const { getUniqueKey, getOutput } = require('./transform-utils');
 | |
| 
 | |
| class SourceMapTransformer {
 | |
|     constructor(finder, opts = {}) {
 | |
|         this.finder = finder;
 | |
|         this.baseDir = opts.baseDir || process.cwd();
 | |
|         this.resolveMapping = opts.getMapping || getMapping;
 | |
|     }
 | |
| 
 | |
|     processFile(fc, sourceMap, coverageMapper) {
 | |
|         let changes = 0;
 | |
| 
 | |
|         Object.entries(fc.statementMap).forEach(([s, loc]) => {
 | |
|             const hits = fc.s[s];
 | |
|             const mapping = this.resolveMapping(sourceMap, loc, fc.path);
 | |
| 
 | |
|             if (mapping) {
 | |
|                 changes += 1;
 | |
|                 const mappedCoverage = coverageMapper(mapping.source);
 | |
|                 mappedCoverage.addStatement(mapping.loc, hits);
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         Object.entries(fc.fnMap).forEach(([f, fnMeta]) => {
 | |
|             const hits = fc.f[f];
 | |
|             const mapping = this.resolveMapping(
 | |
|                 sourceMap,
 | |
|                 fnMeta.decl,
 | |
|                 fc.path
 | |
|             );
 | |
| 
 | |
|             const spanMapping = this.resolveMapping(
 | |
|                 sourceMap,
 | |
|                 fnMeta.loc,
 | |
|                 fc.path
 | |
|             );
 | |
| 
 | |
|             if (
 | |
|                 mapping &&
 | |
|                 spanMapping &&
 | |
|                 mapping.source === spanMapping.source
 | |
|             ) {
 | |
|                 changes += 1;
 | |
|                 const mappedCoverage = coverageMapper(mapping.source);
 | |
|                 mappedCoverage.addFunction(
 | |
|                     fnMeta.name,
 | |
|                     mapping.loc,
 | |
|                     spanMapping.loc,
 | |
|                     hits
 | |
|                 );
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         Object.entries(fc.branchMap).forEach(([b, branchMeta]) => {
 | |
|             const hits = fc.b[b];
 | |
|             const locs = [];
 | |
|             const mappedHits = [];
 | |
|             let source;
 | |
|             let skip;
 | |
| 
 | |
|             branchMeta.locations.forEach((loc, i) => {
 | |
|                 const mapping = this.resolveMapping(sourceMap, loc, fc.path);
 | |
|                 if (mapping) {
 | |
|                     if (!source) {
 | |
|                         source = mapping.source;
 | |
|                     }
 | |
| 
 | |
|                     if (mapping.source !== source) {
 | |
|                         skip = true;
 | |
|                     }
 | |
| 
 | |
|                     locs.push(mapping.loc);
 | |
|                     mappedHits.push(hits[i]);
 | |
|                 }
 | |
|                 // Check if this is an implicit else
 | |
|                 else if (
 | |
|                     source &&
 | |
|                     branchMeta.type === 'if' &&
 | |
|                     i > 0 &&
 | |
|                     loc.start.line === undefined &&
 | |
|                     loc.start.end === undefined &&
 | |
|                     loc.end.line === undefined &&
 | |
|                     loc.end.end === undefined
 | |
|                 ) {
 | |
|                     locs.push(loc);
 | |
|                     mappedHits.push(hits[i]);
 | |
|                 }
 | |
|             });
 | |
| 
 | |
|             const locMapping = branchMeta.loc
 | |
|                 ? this.resolveMapping(sourceMap, branchMeta.loc, fc.path)
 | |
|                 : null;
 | |
| 
 | |
|             if (!skip && locs.length > 0) {
 | |
|                 changes += 1;
 | |
|                 const mappedCoverage = coverageMapper(source);
 | |
|                 mappedCoverage.addBranch(
 | |
|                     branchMeta.type,
 | |
|                     locMapping ? locMapping.loc : locs[0],
 | |
|                     locs,
 | |
|                     mappedHits
 | |
|                 );
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         return changes > 0;
 | |
|     }
 | |
| 
 | |
|     async transform(coverageMap) {
 | |
|         const uniqueFiles = {};
 | |
|         const getMappedCoverage = file => {
 | |
|             const key = getUniqueKey(file);
 | |
|             if (!uniqueFiles[key]) {
 | |
|                 uniqueFiles[key] = {
 | |
|                     file,
 | |
|                     mappedCoverage: new MappedCoverage(file)
 | |
|                 };
 | |
|             }
 | |
| 
 | |
|             return uniqueFiles[key].mappedCoverage;
 | |
|         };
 | |
| 
 | |
|         for (const file of coverageMap.files()) {
 | |
|             const fc = coverageMap.fileCoverageFor(file);
 | |
|             const sourceMap = await this.finder(file, fc);
 | |
| 
 | |
|             if (sourceMap) {
 | |
|                 const changed = this.processFile(
 | |
|                     fc,
 | |
|                     sourceMap,
 | |
|                     getMappedCoverage
 | |
|                 );
 | |
|                 if (!changed) {
 | |
|                     debug(`File [${file}] ignored, nothing could be mapped`);
 | |
|                 }
 | |
|             } else {
 | |
|                 uniqueFiles[getUniqueKey(file)] = {
 | |
|                     file,
 | |
|                     mappedCoverage: new MappedCoverage(fc)
 | |
|                 };
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return libCoverage.createCoverageMap(getOutput(uniqueFiles));
 | |
|     }
 | |
| }
 | |
| 
 | |
| module.exports = {
 | |
|     SourceMapTransformer
 | |
| };
 |