 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>
		
			
				
	
	
		
			271 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * Jake JavaScript build tool
 | |
|  * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *         http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  *
 | |
| */
 | |
| 
 | |
| let path = require('path');
 | |
| let currDir = process.cwd();
 | |
| 
 | |
| /**
 | |
|   @name jake
 | |
|   @namespace jake
 | |
| */
 | |
| /**
 | |
|   @name jake.TestTask
 | |
|   @constructor
 | |
|   @description Instantiating a TestTask creates a number of Jake
 | |
|   Tasks that make running tests for your software easy.
 | |
| 
 | |
|   @param {String} name The name of the project
 | |
|   @param {Function} definition Defines the list of files containing the tests,
 | |
|   and the name of the namespace/task for running them. Will be executed on the
 | |
|   instantiated TestTask (i.e., 'this', will be the TestTask instance), to set
 | |
|   the various instance-propertiess.
 | |
| 
 | |
|   @example
 | |
|   let t = new jake.TestTask('bij-js', function () {
 | |
|     this.testName = 'testSpecial';
 | |
|     this.testFiles.include('test/**');
 | |
|   });
 | |
| 
 | |
|  */
 | |
| let TestTask = function () {
 | |
|   let self = this;
 | |
|   let args = Array.prototype.slice.call(arguments);
 | |
|   let name = args.shift();
 | |
|   let definition = args.pop();
 | |
|   let prereqs = args.pop() || [];
 | |
| 
 | |
|   /**
 | |
|     @name jake.TestTask#testNam
 | |
|     @public
 | |
|     @type {String}
 | |
|     @description The name of the namespace to place the tests in, and
 | |
|     the top-level task for running tests. Defaults to "test"
 | |
|    */
 | |
|   this.testName = 'test';
 | |
| 
 | |
|   /**
 | |
|     @name jake.TestTask#testFiles
 | |
|     @public
 | |
|     @type {jake.FileList}
 | |
|     @description The list of files containing tests to load
 | |
|    */
 | |
|   this.testFiles = new jake.FileList();
 | |
| 
 | |
|   /**
 | |
|     @name jake.TestTask#showDescription
 | |
|     @public
 | |
|     @type {Boolean}
 | |
|     @description Show the created task when doing Jake -T
 | |
|    */
 | |
|   this.showDescription = true;
 | |
| 
 | |
|   /*
 | |
|     @name jake.TestTask#totalTests
 | |
|     @public
 | |
|     @type {Number}
 | |
|     @description The total number of tests to run
 | |
|   */
 | |
|   this.totalTests = 0;
 | |
| 
 | |
|   /*
 | |
|     @name jake.TestTask#executedTests
 | |
|     @public
 | |
|     @type {Number}
 | |
|     @description The number of tests successfully run
 | |
|   */
 | |
|   this.executedTests = 0;
 | |
| 
 | |
|   if (typeof definition == 'function') {
 | |
|     definition.call(this);
 | |
|   }
 | |
| 
 | |
|   if (this.showDescription) {
 | |
|     desc('Run the tests for ' + name);
 | |
|   }
 | |
| 
 | |
|   task(this.testName, prereqs, {async: true}, function () {
 | |
|     let t = jake.Task[this.fullName + ':run'];
 | |
|     t.on('complete', function () {
 | |
|       complete();
 | |
|     });
 | |
|     // Pass args to the namespaced test
 | |
|     t.invoke.apply(t, arguments);
 | |
|   });
 | |
| 
 | |
|   namespace(self.testName, function () {
 | |
| 
 | |
|     let runTask = task('run', {async: true}, function (pat) {
 | |
|       let re;
 | |
|       let testFiles;
 | |
| 
 | |
|       // Don't nest; make a top-level namespace. Don't want
 | |
|       // re-calling from inside to nest infinitely
 | |
|       jake.currentNamespace = jake.defaultNamespace;
 | |
| 
 | |
|       re = new RegExp(pat);
 | |
|       // Get test files that match the passed-in pattern
 | |
|       testFiles = self.testFiles.toArray()
 | |
|         .filter(function (f) {
 | |
|           return (re).test(f);
 | |
|         }) // Don't load the same file multiple times -- should this be in FileList?
 | |
|         .reduce(function (p, c) {
 | |
|           if (p.indexOf(c) < 0) {
 | |
|             p.push(c);
 | |
|           }
 | |
|           return p;
 | |
|         }, []);
 | |
| 
 | |
|       // Create a namespace for all the testing tasks to live in
 | |
|       namespace(self.testName + 'Exec', function () {
 | |
|         // Each test will be a prereq for the dummy top-level task
 | |
|         let prereqs = [];
 | |
|         // Continuation to pass to the async tests, wrapping `continune`
 | |
|         let next = function () {
 | |
|           complete();
 | |
|         };
 | |
|         // Create the task for this test-function
 | |
|         let createTask = function (name, action) {
 | |
|           // If the test-function is defined with a continuation
 | |
|           // param, flag the task as async
 | |
|           let t;
 | |
|           let isAsync = !!action.length;
 | |
| 
 | |
|           // Define the actual namespaced task with the name, the
 | |
|           // wrapped action, and the correc async-flag
 | |
|           t = task(name, createAction(name, action), {
 | |
|             async: isAsync
 | |
|           });
 | |
|           t.once('complete', function () {
 | |
|             self.executedTests++;
 | |
|           });
 | |
|           t._internal = true;
 | |
|           return t;
 | |
|         };
 | |
|         // Used as the action for the defined task for each test.
 | |
|         let createAction = function (n, a) {
 | |
|           // A wrapped function that passes in the `next` function
 | |
|           // for any tasks that run asynchronously
 | |
|           return function () {
 | |
|             let cb;
 | |
|             if (a.length) {
 | |
|               cb = next;
 | |
|             }
 | |
|             if (!(n == 'before' || n == 'after' ||
 | |
|                     /_beforeEach$/.test(n) || /_afterEach$/.test(n))) {
 | |
|               jake.logger.log(n);
 | |
|             }
 | |
|             // 'this' will be the task when action is run
 | |
|             return a.call(this, cb);
 | |
|           };
 | |
|         };
 | |
|           // Dummy top-level task for everything to be prereqs for
 | |
|         let topLevel;
 | |
| 
 | |
|         // Pull in each test-file, and iterate over any exported
 | |
|         // test-functions. Register each test-function as a prereq task
 | |
|         testFiles.forEach(function (file) {
 | |
|           let exp = require(path.join(currDir, file));
 | |
| 
 | |
|           // Create a namespace for each filename, so test-name collisions
 | |
|           // won't be a problem
 | |
|           namespace(file, function () {
 | |
|             let testPrefix = self.testName + 'Exec:' + file + ':';
 | |
|             let testName;
 | |
|             // Dummy task for displaying file banner
 | |
|             testName = '*** Running ' + file + ' ***';
 | |
|             prereqs.push(testPrefix + testName);
 | |
|             createTask(testName, function () {});
 | |
| 
 | |
|             // 'before' setup
 | |
|             if (typeof exp.before == 'function') {
 | |
|               prereqs.push(testPrefix + 'before');
 | |
|               // Create the task
 | |
|               createTask('before', exp.before);
 | |
|             }
 | |
| 
 | |
|             // Walk each exported function, and create a task for each
 | |
|             for (let p in exp) {
 | |
|               if (p == 'before' || p == 'after' ||
 | |
|                   p == 'beforeEach' || p == 'afterEach') {
 | |
|                 continue;
 | |
|               }
 | |
| 
 | |
|               if (typeof exp.beforeEach == 'function') {
 | |
|                 prereqs.push(testPrefix + p + '_beforeEach');
 | |
|                 // Create the task
 | |
|                 createTask(p + '_beforeEach', exp.beforeEach);
 | |
|               }
 | |
| 
 | |
|               // Add the namespace:name of this test to the list of prereqs
 | |
|               // for the dummy top-level task
 | |
|               prereqs.push(testPrefix + p);
 | |
|               // Create the task
 | |
|               createTask(p, exp[p]);
 | |
| 
 | |
|               if (typeof exp.afterEach == 'function') {
 | |
|                 prereqs.push(testPrefix + p + '_afterEach');
 | |
|                 // Create the task
 | |
|                 createTask(p + '_afterEach', exp.afterEach);
 | |
|               }
 | |
|             }
 | |
| 
 | |
|             // 'after' teardown
 | |
|             if (typeof exp.after == 'function') {
 | |
|               prereqs.push(testPrefix + 'after');
 | |
|               // Create the task
 | |
|               let afterTask = createTask('after', exp.after);
 | |
|               afterTask._internal = true;
 | |
|             }
 | |
| 
 | |
|           });
 | |
|         });
 | |
| 
 | |
|         self.totalTests = prereqs.length;
 | |
|         process.on('exit', function () {
 | |
|           // Throw in the case where the process exits without
 | |
|           // finishing tests, but no error was thrown
 | |
|           if (!jake.errorCode && (self.totalTests > self.executedTests)) {
 | |
|             throw new Error('Process exited without all tests completing.');
 | |
|           }
 | |
|         });
 | |
| 
 | |
|         // Create the dummy top-level task. When calling a task internally
 | |
|         // with `invoke` that is async (or has async prereqs), have to listen
 | |
|         // for the 'complete' event to know when it's done
 | |
|         topLevel = task('__top__', prereqs);
 | |
|         topLevel._internal = true;
 | |
|         topLevel.addListener('complete', function () {
 | |
|           jake.logger.log('All tests ran successfully');
 | |
|           complete();
 | |
|         });
 | |
| 
 | |
|         topLevel.invoke(); // Do the thing!
 | |
|       });
 | |
| 
 | |
|     });
 | |
|     runTask._internal = true;
 | |
| 
 | |
|   });
 | |
| 
 | |
| 
 | |
| };
 | |
| 
 | |
| jake.TestTask = TestTask;
 | |
| exports.TestTask = TestTask;
 | |
| 
 |