Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion scripts/check-project-structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ type CheckResult = {
errors: string[];
};

/**
* Validate that a scaffolded project path exists, is a directory, and contains a file named `package.json`.
*
* @param projectPath - Filesystem path to the project directory to validate
* @returns A `CheckResult` where `passed` is `true` if all checks succeed; otherwise `passed` is `false` and `errors` contains descriptive failure messages
*/
export function checkProjectStructure(projectPath: string): CheckResult {
const errors: string[] = [];

Expand Down Expand Up @@ -79,4 +85,3 @@ if (require.main === module) {
process.exit(1);
}
}

16 changes: 15 additions & 1 deletion scripts/functional-tests/api-endpoint-tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ export type APIEndpointResult = {
warnings: string[];
};

/**
* Performs API endpoint checks against a scaffolded project.
*
* The function attempts to validate the project's HTTP endpoints given a running server. Currently the implementation is a placeholder that records informational warnings about incomplete testing and the need for a reachable server.
*
* @param _projectPath - Filesystem path to the project whose endpoints should be tested
* @param _serverUrl - Base URL of the running server to test against (e.g., `http://localhost:3000`)
* @param _config - Optional test configuration:
* - `authProvider`: name of the authentication provider to consider when selecting auth-related checks
* - `frontends`: list of frontend identifiers (for example `['react','vue']`) to guide frontend-specific route checks
* @returns An object describing the results:
* - `passed`: `true` if all executed checks passed, `false` otherwise
* - `errors`: array of failure messages for checks that did not pass
* - `warnings`: array of informational messages or reminders (currently includes placeholders about incomplete implementation and server availability)
*/
export async function testAPIEndpoints(
_projectPath: string,
_serverUrl: string = 'http://localhost:3000',
Expand Down Expand Up @@ -70,4 +85,3 @@ if (require.main === module) {
process.exit(1);
});
}

28 changes: 27 additions & 1 deletion scripts/functional-tests/auth-test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ type AuthTestResult = {

const SUPPORTED_DATABASE_ENGINES = new Set(['sqlite', 'mongodb']);

/**
* Constructs a deterministic, filesystem-safe project name for a scaffolded auth test from a test matrix entry.
*
* @param config - Configuration entry describing frontend, database engine, ORM, database host, and tailwind usage
* @returns A normalized project name of the form `test-auth-<frontend>-<databaseEngine>-<orm>-<databaseHostLabel>-<tw|notw>`
*/
function buildProjectName(config: TestMatrixEntry): string {
const hostLabel = config.databaseHost === 'none' ? 'local' : config.databaseHost;
const tailwindLabel = config.useTailwind ? 'tw' : 'notw';
Expand All @@ -41,6 +47,13 @@ function buildProjectName(config: TestMatrixEntry): string {
.replace(/-+/g, '-');
}

/**
* Build the Bun CLI argument list to scaffold a project that matches the provided test configuration.
*
* @param projectName - Target project name used by the scaffold command
* @param config - Test matrix entry whose fields determine which CLI flags are appended
* @returns An array of command arguments for invoking the scaffold script (base command plus flags that reflect frontend, database engine, ORM, database host, auth provider, code quality tool, Tailwind usage, and directory configuration)
*/
function buildScaffoldCommand(
projectName: string,
config: TestMatrixEntry
Expand Down Expand Up @@ -90,6 +103,12 @@ function buildScaffoldCommand(
return cmd;
}

/**
* Scaffolds a project for the given test configuration, runs dependency installation and auth validation, and aggregates results.
*
* @param config - A test matrix entry describing the project configuration to scaffold and validate (frontend, databaseEngine, orm, databaseHost, authProvider, codeQualityTool, useTailwind, directoryConfig).
* @returns An AuthTestResult describing the evaluated configuration, whether validation passed, collected error and warning messages, and the total test duration in milliseconds (`testTime`).
*/
async function scaffoldAndTestAuth(
config: TestMatrixEntry
): Promise<AuthTestResult> {
Expand Down Expand Up @@ -264,6 +283,14 @@ async function scaffoldAndTestAuth(
}
}

/**
* Runs auth validation across a matrix of test configurations and exits the process with a success or failure code.
*
* Reads the JSON matrix from `matrixFile`, filters entries to those with an auth provider and a supported database engine, and (optionally) limits the set to the first `testSubset` entries. For each configuration it scaffolds, installs, and validates the project, printing per-config progress and a final summary. If any configuration fails validation, the process exits with code `1`; if all pass, the process exits with code `0`.
*
* @param matrixFile - Path to the JSON test matrix file (defaults to 'test-matrix.json')
* @param testSubset - Optional maximum number of configurations from the filtered set to test
*/
async function runAuthTests(
matrixFile: string = 'test-matrix.json',
testSubset?: number
Expand Down Expand Up @@ -340,4 +367,3 @@ if (require.main === module) {
});
}


18 changes: 17 additions & 1 deletion scripts/functional-tests/auth-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,23 @@ const relationalEngines = new Set([
'mysql'
]);

/**
* Validates that a scaffolded project's authentication configuration and wiring are present and correct.
*
* Performs checks for a user handler, database schema (engine- and ORM-aware), server plugin wiring, and
* presence of the `@absolutejs/auth` dependency, then optionally runs shared functional tests and aggregates results.
*
* @param projectPath - Filesystem path to the project root to validate
* @param packageManager - Package manager to use when running functional tests (`bun`, `npm`, `pnpm`, or `yarn`)
* @param config - Validator configuration: may include `databaseEngine` (e.g., 'sqlite', 'postgresql', 'mysql', 'mongodb', or 'none'), `orm` (e.g., 'drizzle'), and `authProvider`
* @param options - Runtime options to alter test behavior; supports `skipDependencies`, `skipBuild`, and `skipServer` flags
* @returns An AuthValidationResult containing:
* - `passed`: `true` if all required checks and (if run) functional tests passed, `false` otherwise;
* - `errors`: list of failure messages observed during validation;
* - `warnings`: list of non-fatal observations or coverage gaps;
* - `functionalTestResults` (optional): aggregated results from the shared functional test suite when executed;
* - `authSpecific`: object with boolean flags `handlerExists`, `schemaIncludesUsers`, `serverUsesAuth`, and `packageHasAuthDependency` indicating individual check outcomes.
*/
export async function validateAuthConfiguration(
projectPath: string,
packageManager: 'bun' | 'npm' | 'pnpm' | 'yarn' = 'bun',
Expand Down Expand Up @@ -273,4 +290,3 @@ if (require.main === module) {
});
}


9 changes: 7 additions & 2 deletions scripts/functional-tests/build-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ export type BuildResult = {
compileTime?: number;
};

const COMPILE_TIMEOUT = 60000; // 60 seconds
const COMPILE_TIMEOUT = 60000; /**
* Validates that a scaffolded project compiles by checking for tsconfig.json, ensuring package.json has a `typecheck` script, and running that script.
*
* @param projectPath - Path to the project directory to validate
* @param packageManager - Package manager to run the `typecheck` script with (`'bun' | 'npm' | 'pnpm' | 'yarn'`); defaults to `'bun'`
* @returns A BuildResult where `passed` is `true` when compilation succeeds, `errors` contains failure messages when present, and `compileTime` (milliseconds) is included when a compilation attempt was performed
*/

export async function validateBuild(
projectPath: string,
Expand Down Expand Up @@ -137,4 +143,3 @@ if (import.meta.main) {
process.exit(1);
});
}

15 changes: 14 additions & 1 deletion scripts/functional-tests/cloud-provider-test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ type CloudProviderTestResult = {
testTime?: number;
};

/**
* Scaffolds a deterministic test project for the given matrix entry, installs dependencies, runs cloud-provider validation, cleans up artifacts, and returns the aggregated test result.
*
* @param config - Test matrix entry describing frontend, databaseEngine, orm, databaseHost, authProvider, and related test options used to build and validate the project
* @returns A CloudProviderTestResult containing the original `config`, a `passed` flag, collected `errors` and `warnings`, and `testTime` in milliseconds
*/
async function scaffoldAndTestCloudProvider(
config: TestMatrixEntry
): Promise<CloudProviderTestResult> {
Expand Down Expand Up @@ -289,6 +295,14 @@ async function scaffoldAndTestCloudProvider(
}
}

/**
* Orchestrates cloud provider validation across a set of test matrix entries and exits with a non-zero code if any configuration fails.
*
* Reads a JSON test matrix, filters entries for supported cloud-provider combinations, optionally limits the run to a subset, and for each configuration scaffolds a project, installs dependencies, runs validation, and aggregates results into a summary grouped by provider.
*
* @param matrixFile - Path to the JSON test matrix file (defaults to "test-matrix.json")
* @param testSubset - Optional maximum number of configurations to test (if provided, runs only the first N matching entries)
*/
async function runCloudProviderTests(
matrixFile: string = 'test-matrix.json',
testSubset?: number
Expand Down Expand Up @@ -399,4 +413,3 @@ async function runCloudProviderTests(
if (require.main === module) {
runCloudProviderTests().catch(console.error);
}

21 changes: 20 additions & 1 deletion scripts/functional-tests/cloud-provider-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ export type CloudProviderValidationResult = {
};
};

/**
* Validates a project's cloud database provider setup (Neon, PlanetScale, or Turso), verifies provider-specific code, imports and dependencies, checks environment configuration and Docker usage, and runs functional tests.
*
* @param projectPath - Path to the project root being validated.
* @param packageManager - Package manager to use when running functional tests (`bun` | `npm` | `pnpm` | `yarn`).
* @param config - Optional configuration that influences validation:
* - `databaseHost`: provider identifier (`neon`, `planetscale`, or `turso`) used to select provider-specific checks.
* - `orm`: ORM in use (e.g., `drizzle`) which adjusts Neon connection/import expectations.
* - `databaseEngine` and `authProvider` are accepted but not required for provider selection.
* @param options - Execution options forwarded to the functional test runner:
* - `skipDependencies`: skip dependency installation step.
* - `skipBuild`: skip build step.
* - `skipServer`: skip starting the server for runtime checks.
* @returns The CloudProviderValidationResult containing:
* - `passed`: whether the validation succeeded,
* - `errors`: array of error messages,
* - `warnings`: array of warnings,
* - `functionalTestResults` (when available),
* - `cloudSpecific`: detailed booleans for connection code, imports, dependencies, Docker presence, and env configuration.
*/
export async function validateCloudProvider(
projectPath: string,
packageManager: 'bun' | 'npm' | 'pnpm' | 'yarn' = 'bun',
Expand Down Expand Up @@ -301,4 +321,3 @@ if (require.main === module) {
process.exit(1);
});
}

18 changes: 17 additions & 1 deletion scripts/functional-tests/database-connection-tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ export type DatabaseConnectionResult = {
warnings: string[];
};

/**
* Performs basic checks to validate a project's database setup and returns structured results.
*
* The function verifies whether a database is configured, checks for a `db` directory under the project path,
* and performs an ORM-specific check for a Drizzle schema (`db/schema.ts`). It also emits warnings that the
* connection tests are not fully implemented and may require Docker or cloud credentials.
*
* @param projectPath - Filesystem path to the project root where the `db` directory is expected
* @param config - Optional configuration for the check:
* - `databaseEngine`: name of the configured database engine or `'none'` to indicate no DB
* - `databaseHost`: hostname for the database (unused by this basic tester)
* - `orm`: ORM in use; when `'drizzle'`, the presence of `db/schema.ts` is validated
* @returns An object with:
* - `passed`: `true` if checks completed without errors, `false` if one or more errors were found
* - `errors`: list of error messages describing failing checks
* - `warnings`: list of informational warnings (for example, when database testing is not implemented or when no DB is configured)
*/
export async function testDatabaseConnection(
projectPath: string,
config: {
Expand Down Expand Up @@ -95,4 +112,3 @@ if (require.main === module) {
process.exit(1);
});
}

32 changes: 25 additions & 7 deletions scripts/functional-tests/dependency-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ type DependencyFingerprint = {
};

/**
* Generate a unique cache key based on dependencies
* Configs with same dependencies will share the same cache
* Produce a stable fingerprint string for a dependency configuration.
*
* @param config - Dependency fields that affect installed packages; fields considered include `frontend`, `databaseEngine`, `orm`, `databaseHost`, `authProvider`, `useTailwind`, and `codeQualityTool`.
* @returns A 16-character hexadecimal fingerprint identifying the provided dependency configuration.
*/
function getDependencyFingerprint(config: DependencyFingerprint): string {
// Normalize the config to create a stable fingerprint
Expand All @@ -41,14 +43,20 @@ function getDependencyFingerprint(config: DependencyFingerprint): string {
const CACHE_DIR = join(process.cwd(), '.test-dependency-cache');

/**
* Get the cache path for a dependency fingerprint
* Return the cache directory path for a given dependency fingerprint.
*
* @param fingerprint - The fingerprint identifying a dependency configuration
* @returns The filesystem path to the cache directory for `fingerprint`
*/
function getCachePath(fingerprint: string): string {
return join(CACHE_DIR, fingerprint);
}

/**
* Check if a cached node_modules exists for this fingerprint
* Determine whether a cached node_modules directory exists for the given dependency fingerprint.
*
* @param config - Dependency fingerprint describing the dependencies and configuration that affect installed packages
* @returns `true` if a cached `node_modules` directory exists for the fingerprint, `false` otherwise
*/
export function hasCachedDependencies(config: DependencyFingerprint): boolean {
const fingerprint = getDependencyFingerprint(config);
Expand All @@ -59,7 +67,14 @@ export function hasCachedDependencies(config: DependencyFingerprint): boolean {
}

/**
* Get cached node_modules or install and cache them
* Ensure the project has a populated `node_modules` directory by restoring from a fingerprinted cache when available, otherwise installing dependencies and storing them in the cache.
*
* @param projectPath - Filesystem path to the project where `node_modules` will be placed
* @param config - Dependency fingerprint describing the dependency/configuration set used to derive the cache key
* @param packageJsonPath - Path to the project's `package.json`; when present it is copied into the cache for reference
* @returns An object with `cached` set to `true` if dependencies were restored from the cache (otherwise `false`), and `installTime` representing the operation duration in milliseconds
* @throws Error if dependency installation times out after 300 seconds
* @throws Error if the dependency installer exits with a non-zero exit code
*/
export async function getOrInstallDependencies(
projectPath: string,
Expand Down Expand Up @@ -126,7 +141,11 @@ export async function getOrInstallDependencies(
}

/**
* Clean up old cache entries (optional - can be called periodically)
* Remove cached dependency entries older than the given number of days.
*
* This is a placeholder implementation that currently performs no deletions.
*
* @param maxAgeDays - Maximum age in days for cache entries before they are removed (default: 7)
*/
export function cleanupCache(maxAgeDays: number = 7): void {
if (!existsSync(CACHE_DIR)) {
Expand All @@ -139,4 +158,3 @@ export function cleanupCache(maxAgeDays: number = 7): void {
// This would require reading directory entries - simplified for now
// In production, you might want to add cache metadata files with timestamps
}

15 changes: 13 additions & 2 deletions scripts/functional-tests/dependency-installer-tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,19 @@ export type DependencyInstallResult = {
installTime?: number;
};

const INSTALL_TIMEOUT = 120000; // 2 minutes for dependency installation
const INSTALL_TIMEOUT = 120000; /**
* Tests whether dependencies in a scaffolded project can be installed with the specified package manager.
*
* Attempts to parse the project's package.json, skip installation if no dependencies are declared, run the appropriate
* install command (within a 2-minute timeout), and verify that node_modules is created.
*
* @param projectPath - Path to the project directory containing package.json
* @param packageManager - Package manager to use for installation: 'bun', 'npm', 'pnpm', or 'yarn' (default: 'bun')
* @returns An object describing the result:
* - `passed`: `true` when installation succeeded or no dependencies were present, `false` otherwise.
* - `errors`: Array of human-readable error messages collected during checks or installation.
* - `installTime` (optional): Time in milliseconds the installation process took when an install was attempted.
*/

export async function testDependencyInstallation(
projectPath: string,
Expand Down Expand Up @@ -157,4 +169,3 @@ if (require.main === module) {
process.exit(1);
});
}

10 changes: 9 additions & 1 deletion scripts/functional-tests/frontend-renderer-tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ export type FrontendRendererResult = {
warnings: string[];
};

/**
* Runs a placeholder frontend rendering test for the specified project and collects warnings about unimplemented checks.
*
* @param projectPath - Path to the project's root directory to inspect and test
* @param serverUrl - Base URL of the running application to target (defaults to `http://localhost:3000`)
* @param config - Optional configuration for the test
* @param config.frontends - Optional list of frontend frameworks (e.g., `['react','vue']`) to focus testing on
* @returns A FrontendRendererResult where `passed` is `true` if no errors were recorded, `errors` contains error messages, and `warnings` contains informational warnings about incomplete or skipped checks
*/
export async function testFrontendRendering(
projectPath: string,
serverUrl: string = 'http://localhost:3000',
Expand Down Expand Up @@ -76,4 +85,3 @@ if (require.main === module) {
process.exit(1);
});
}

18 changes: 17 additions & 1 deletion scripts/functional-tests/functional-test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ export type FunctionalTestResult = {
totalTime?: number;
};

/**
* Runs a sequence of functional tests (project structure, dependency installation, build validation, and server startup) for the given project and aggregates the results.
*
* The dependency installation, build, and server startup tests can be individually skipped via the `options` flags. Results include per-step pass/fail and timing where applicable, along with collected errors and warnings.
*
* @param projectPath - Filesystem path to the project to test
* @param packageManager - Package manager to use (`'bun' | 'npm' | 'pnpm' | 'yarn'`)
* @param options.skipDependencies - When true, skips the dependency installation test
* @param options.skipBuild - When true, skips the build validation test
* @param options.skipServer - When true, skips the server startup validation test
* @returns The consolidated functional test result containing:
* - `passed`: `true` if no errors were recorded, `false` otherwise
* - `errors`: array of error messages collected from failing steps
* - `warnings`: array of warnings (including notifications for skipped tests)
* - `results`: per-step results with optional timing fields (`installTime`, `compileTime`)
* - `totalTime`: total duration in milliseconds for the entire run
*/
export async function runFunctionalTests(
projectPath: string,
packageManager: 'bun' | 'npm' | 'pnpm' | 'yarn' = 'bun',
Expand Down Expand Up @@ -185,4 +202,3 @@ if (require.main === module) {
process.exit(1);
});
}

Loading