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:
anthonyrawlins
2025-07-11 14:06:34 +10:00
parent c6d69695a8
commit aacb45156b
6109 changed files with 777927 additions and 1 deletions

666
frontend/node_modules/tldts/dist/cjs/index.js generated vendored Normal file

File diff suppressed because one or more lines are too long

1
frontend/node_modules/tldts/dist/cjs/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

14
frontend/node_modules/tldts/dist/cjs/src/data/trie.js generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = suffixLookup;
const tldts_core_1 = require("tldts-core");
const trie_1 = require("./data/trie");
/**
* Lookup parts of domain in Trie
*/
function lookupInTrie(parts, trie, index, allowedMask) {
let result = null;
let node = trie;
while (node !== undefined) {
// We have a match!
if ((node[0] & allowedMask) !== 0) {
result = {
index: index + 1,
isIcann: node[0] === 1 /* RULE_TYPE.ICANN */,
isPrivate: node[0] === 2 /* RULE_TYPE.PRIVATE */,
};
}
// No more `parts` to look for
if (index === -1) {
break;
}
const succ = node[1];
node = Object.prototype.hasOwnProperty.call(succ, parts[index])
? succ[parts[index]]
: succ['*'];
index -= 1;
}
return result;
}
/**
* Check if `hostname` has a valid public suffix in `trie`.
*/
function suffixLookup(hostname, options, out) {
var _a;
if ((0, tldts_core_1.fastPathLookup)(hostname, options, out)) {
return;
}
const hostnameParts = hostname.split('.');
const allowedMask = (options.allowPrivateDomains ? 2 /* RULE_TYPE.PRIVATE */ : 0) |
(options.allowIcannDomains ? 1 /* RULE_TYPE.ICANN */ : 0);
// Look for exceptions
const exceptionMatch = lookupInTrie(hostnameParts, trie_1.exceptions, hostnameParts.length - 1, allowedMask);
if (exceptionMatch !== null) {
out.isIcann = exceptionMatch.isIcann;
out.isPrivate = exceptionMatch.isPrivate;
out.publicSuffix = hostnameParts.slice(exceptionMatch.index + 1).join('.');
return;
}
// Look for a match in rules
const rulesMatch = lookupInTrie(hostnameParts, trie_1.rules, hostnameParts.length - 1, allowedMask);
if (rulesMatch !== null) {
out.isIcann = rulesMatch.isIcann;
out.isPrivate = rulesMatch.isPrivate;
out.publicSuffix = hostnameParts.slice(rulesMatch.index).join('.');
return;
}
// No match found...
// Prevailing rule is '*' so we consider the top-level domain to be the
// public suffix of `hostname` (e.g.: 'example.org' => 'org').
out.isIcann = false;
out.isPrivate = false;
out.publicSuffix = (_a = hostnameParts[hostnameParts.length - 1]) !== null && _a !== void 0 ? _a : null;
}
//# sourceMappingURL=suffix-trie.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"suffix-trie.js","sourceRoot":"","sources":["../../../src/suffix-trie.ts"],"names":[],"mappings":"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"}

File diff suppressed because one or more lines are too long

33
frontend/node_modules/tldts/dist/es6/index.js generated vendored Normal file
View File

@@ -0,0 +1,33 @@
import { getEmptyResult, parseImpl, resetResult, } from 'tldts-core';
import suffixLookup from './src/suffix-trie';
// For all methods but 'parse', it does not make sense to allocate an object
// every single time to only return the value of a specific attribute. To avoid
// this un-necessary allocation, we use a global object which is re-used.
const RESULT = getEmptyResult();
export function parse(url, options = {}) {
return parseImpl(url, 5 /* FLAG.ALL */, suffixLookup, options, getEmptyResult());
}
export function getHostname(url, options = {}) {
/*@__INLINE__*/ resetResult(RESULT);
return parseImpl(url, 0 /* FLAG.HOSTNAME */, suffixLookup, options, RESULT).hostname;
}
export function getPublicSuffix(url, options = {}) {
/*@__INLINE__*/ resetResult(RESULT);
return parseImpl(url, 2 /* FLAG.PUBLIC_SUFFIX */, suffixLookup, options, RESULT)
.publicSuffix;
}
export function getDomain(url, options = {}) {
/*@__INLINE__*/ resetResult(RESULT);
return parseImpl(url, 3 /* FLAG.DOMAIN */, suffixLookup, options, RESULT).domain;
}
export function getSubdomain(url, options = {}) {
/*@__INLINE__*/ resetResult(RESULT);
return parseImpl(url, 4 /* FLAG.SUB_DOMAIN */, suffixLookup, options, RESULT)
.subdomain;
}
export function getDomainWithoutSuffix(url, options = {}) {
/*@__INLINE__*/ resetResult(RESULT);
return parseImpl(url, 5 /* FLAG.ALL */, suffixLookup, options, RESULT)
.domainWithoutSuffix;
}
//# sourceMappingURL=index.js.map

1
frontend/node_modules/tldts/dist/es6/index.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EAGd,SAAS,EACT,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAE7C,4EAA4E;AAC5E,+EAA+E;AAC/E,yEAAyE;AACzE,MAAM,MAAM,GAAY,cAAc,EAAE,CAAC;AAEzC,MAAM,UAAU,KAAK,CAAC,GAAW,EAAE,UAA6B,EAAE;IAChE,OAAO,SAAS,CAAC,GAAG,oBAAY,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAW,EACX,UAA6B,EAAE;IAE/B,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC,GAAG,yBAAiB,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,GAAW,EACX,UAA6B,EAAE;IAE/B,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC,GAAG,8BAAsB,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC;SACrE,YAAY,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,GAAW,EACX,UAA6B,EAAE;IAE/B,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC,GAAG,uBAAe,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,GAAW,EACX,UAA6B,EAAE;IAE/B,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC,GAAG,2BAAmB,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC;SAClE,SAAS,CAAC;AACf,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,GAAW,EACX,UAA6B,EAAE;IAE/B,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC,GAAG,oBAAY,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC;SAC3D,mBAAmB,CAAC;AACzB,CAAC"}

11
frontend/node_modules/tldts/dist/es6/src/data/trie.js generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,64 @@
import { fastPathLookup, } from 'tldts-core';
import { exceptions, rules } from './data/trie';
/**
* Lookup parts of domain in Trie
*/
function lookupInTrie(parts, trie, index, allowedMask) {
let result = null;
let node = trie;
while (node !== undefined) {
// We have a match!
if ((node[0] & allowedMask) !== 0) {
result = {
index: index + 1,
isIcann: node[0] === 1 /* RULE_TYPE.ICANN */,
isPrivate: node[0] === 2 /* RULE_TYPE.PRIVATE */,
};
}
// No more `parts` to look for
if (index === -1) {
break;
}
const succ = node[1];
node = Object.prototype.hasOwnProperty.call(succ, parts[index])
? succ[parts[index]]
: succ['*'];
index -= 1;
}
return result;
}
/**
* Check if `hostname` has a valid public suffix in `trie`.
*/
export default function suffixLookup(hostname, options, out) {
var _a;
if (fastPathLookup(hostname, options, out)) {
return;
}
const hostnameParts = hostname.split('.');
const allowedMask = (options.allowPrivateDomains ? 2 /* RULE_TYPE.PRIVATE */ : 0) |
(options.allowIcannDomains ? 1 /* RULE_TYPE.ICANN */ : 0);
// Look for exceptions
const exceptionMatch = lookupInTrie(hostnameParts, exceptions, hostnameParts.length - 1, allowedMask);
if (exceptionMatch !== null) {
out.isIcann = exceptionMatch.isIcann;
out.isPrivate = exceptionMatch.isPrivate;
out.publicSuffix = hostnameParts.slice(exceptionMatch.index + 1).join('.');
return;
}
// Look for a match in rules
const rulesMatch = lookupInTrie(hostnameParts, rules, hostnameParts.length - 1, allowedMask);
if (rulesMatch !== null) {
out.isIcann = rulesMatch.isIcann;
out.isPrivate = rulesMatch.isPrivate;
out.publicSuffix = hostnameParts.slice(rulesMatch.index).join('.');
return;
}
// No match found...
// Prevailing rule is '*' so we consider the top-level domain to be the
// public suffix of `hostname` (e.g.: 'example.org' => 'org').
out.isIcann = false;
out.isPrivate = false;
out.publicSuffix = (_a = hostnameParts[hostnameParts.length - 1]) !== null && _a !== void 0 ? _a : null;
}
//# sourceMappingURL=suffix-trie.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"suffix-trie.js","sourceRoot":"","sources":["../../../src/suffix-trie.ts"],"names":[],"mappings":"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"}

File diff suppressed because one or more lines are too long

2
frontend/node_modules/tldts/dist/index.cjs.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
frontend/node_modules/tldts/dist/index.esm.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
frontend/node_modules/tldts/dist/index.umd.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

7
frontend/node_modules/tldts/dist/types/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import { IOptions, IResult } from 'tldts-core';
export declare function parse(url: string, options?: Partial<IOptions>): IResult;
export declare function getHostname(url: string, options?: Partial<IOptions>): string | null;
export declare function getPublicSuffix(url: string, options?: Partial<IOptions>): string | null;
export declare function getDomain(url: string, options?: Partial<IOptions>): string | null;
export declare function getSubdomain(url: string, options?: Partial<IOptions>): string | null;
export declare function getDomainWithoutSuffix(url: string, options?: Partial<IOptions>): string | null;

View File

@@ -0,0 +1,5 @@
export type ITrie = [0 | 1 | 2, {
[label: string]: ITrie;
}];
export declare const exceptions: ITrie;
export declare const rules: ITrie;

View File

@@ -0,0 +1,5 @@
import { IPublicSuffix, ISuffixLookupOptions } from 'tldts-core';
/**
* Check if `hostname` has a valid public suffix in `trie`.
*/
export default function suffixLookup(hostname: string, options: ISuffixLookupOptions, out: IPublicSuffix): void;