diff --git a/README.md b/README.md index 4a29bfc6..7720d86d 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ yarn shortest export default { headless: false, baseUrl: 'http://localhost:3000', - testDir: 'app/__tests__', + testPattern: '**/*.test.ts', anthropicKey: process.env.ANTHROPIC_API_KEY } satisfies ShortestConfig; ``` diff --git a/app/__tests__/dashboard.test.ts b/app/(dashboard)/page.test.ts similarity index 77% rename from app/__tests__/dashboard.test.ts rename to app/(dashboard)/page.test.ts index 19612144..4d80bbff 100644 --- a/app/__tests__/dashboard.test.ts +++ b/app/(dashboard)/page.test.ts @@ -1,5 +1,6 @@ import { shortest } from "@antiwork/shortest"; +shortest("Verify that buttons are rounded on the landing page"); shortest( "Login to the App using magic link. Use this email: 'mission-health@rdt7stzf.mailosaur.net'", ); diff --git a/license.md b/license.md index d378ff9b..ed0ccfa3 100644 --- a/license.md +++ b/license.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2024 Gumroad, Inc. +Copyright (c) 2025 Gumroad, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/packages/shortest/README.md b/packages/shortest/README.md index 52e9e208..14e9aa67 100644 --- a/packages/shortest/README.md +++ b/packages/shortest/README.md @@ -32,7 +32,7 @@ import type { ShortestConfig } from '@antiwork/shortest'; export default { headless: false, baseUrl: 'http://localhost:3000', - testDir: 'app/__tests__', + testPattern: "**/*.test.ts", anthropicKey: process.env.ANTHROPIC_API_KEY } satisfies ShortestConfig; ``` diff --git a/packages/shortest/src/cli/bin.ts b/packages/shortest/src/cli/bin.ts index 646a6489..f9cc5f95 100644 --- a/packages/shortest/src/cli/bin.ts +++ b/packages/shortest/src/cli/bin.ts @@ -1,6 +1,7 @@ #!/usr/bin/env node import pc from "picocolors"; +import { getConfig } from ".."; import { GitHubTool } from "../browser/integrations/github"; import { TestRunner } from "../core/runner"; @@ -132,7 +133,7 @@ async function main() { const targetUrl = args .find((arg) => arg.startsWith("--target=")) ?.split("=")[1]; - const testPattern = args.find((arg) => !arg.startsWith("--")); + const cliTestPattern = args.find((arg) => !arg.startsWith("--")); const debugAI = args.includes("--debug-ai"); const noCache = args.includes("--no-cache"); @@ -146,12 +147,9 @@ async function main() { noCache, ); await runner.initialize(); - - if (testPattern) { - await runner.runFile(testPattern); - } else { - await runner.runAll(); - } + const config = getConfig(); + const testPattern = cliTestPattern || config.testPattern; + await runner.runTests(testPattern); } catch (error) { if (error instanceof Error) { if (error.message.includes("Config")) { @@ -164,7 +162,7 @@ async function main() { ); console.error(pc.dim(" - headless: boolean")); console.error(pc.dim(" - baseUrl: string")); - console.error(pc.dim(" - testDir: string | string[]")); + console.error(pc.dim(" - testPattern: string")); console.error(pc.dim(" - anthropicKey: string")); console.error(); } else { diff --git a/packages/shortest/src/core/runner/index.ts b/packages/shortest/src/core/runner/index.ts index c9cf6126..55c2f3a6 100644 --- a/packages/shortest/src/core/runner/index.ts +++ b/packages/shortest/src/core/runner/index.ts @@ -1,4 +1,3 @@ -import { resolve } from "path"; import Anthropic from "@anthropic-ai/sdk"; import { glob } from "glob"; import pc from "picocolors"; @@ -83,37 +82,17 @@ export class TestRunner { } private async findTestFiles(pattern?: string): Promise { - const testDirs = Array.isArray(this.config.testDir) - ? this.config.testDir - : [this.config.testDir || "__tests__"]; - - const files = []; - for (const dir of testDirs) { - if (pattern) { - const cleanPattern = pattern - .replace(/\.ts$/, "") - .replace(/\.test$/, "") - .split("/") - .pop(); - - const globPattern = `${dir}/**/${cleanPattern}.test.ts`; - const matches = await glob(globPattern, { - cwd: this.cwd, - absolute: true, - }); - - files.push(...matches); - } else { - const globPattern = `${dir}/**/*.test.ts`; - const matches = await glob(globPattern, { cwd: this.cwd }); - files.push(...matches.map((f) => resolve(this.cwd, f))); - } - } + const testPattern = pattern || this.config.testPattern || "**/*.test.ts"; + + const files = await glob(testPattern, { + cwd: this.cwd, + absolute: true, + }); if (files.length === 0) { this.logger.error( "Test Discovery", - `No test files found in directories: ${testDirs.join(", ")}`, + `No test files found matching: ${testPattern}`, ); process.exit(1); } @@ -224,7 +203,7 @@ export class TestRunner { }`, ), ] - : []), + : ["\nExpect:", `1. "${test.name}" expected to be successful`]), "\nCurrent Page State:", `URL: ${initialState.metadata?.window_info?.url || "unknown"}`, @@ -386,14 +365,14 @@ export class TestRunner { } } - async runFile(pattern: string) { + async runTests(pattern?: string) { await this.initialize(); const files = await this.findTestFiles(pattern); if (files.length === 0) { this.logger.error( "Test Discovery", - `No test files found matching: ${pattern}`, + `No test files found matching the pattern: ${pattern || this.config.testPattern}`, ); process.exit(1); } @@ -411,23 +390,6 @@ export class TestRunner { } } - async runAll() { - await this.initialize(); - const files = await this.findTestFiles(); - - for (const file of files) { - await this.executeTestFile(file); - } - - this.logger.summary(); - - if (this.exitOnSuccess && this.logger.allTestsPassed()) { - process.exit(0); - } else { - process.exit(1); - } - } - private async runCachedTest( test: TestFunction, browserTool: BrowserTool, diff --git a/packages/shortest/src/index.ts b/packages/shortest/src/index.ts index 3f9e86d8..eb5f7f0f 100644 --- a/packages/shortest/src/index.ts +++ b/packages/shortest/src/index.ts @@ -47,7 +47,7 @@ function validateConfig(config: Partial) { if (config.headless === undefined) missingFields.push("headless"); if (!config.baseUrl) missingFields.push("baseUrl"); - if (!config.testDir) missingFields.push("testDir"); + if (!config.testPattern) missingFields.push("testPattern"); if (!config.anthropicKey && !process.env.ANTHROPIC_API_KEY) missingFields.push("anthropicKey"); @@ -98,7 +98,7 @@ export async function initialize() { "Required fields:\n" + " - headless: boolean\n" + " - baseUrl: string\n" + - " - testDir: string | string[]\n" + + " - testPattern: string\n" + " - anthropicKey: string", ); } diff --git a/packages/shortest/src/types/config.ts b/packages/shortest/src/types/config.ts index fdcd23ab..9fdd05ed 100644 --- a/packages/shortest/src/types/config.ts +++ b/packages/shortest/src/types/config.ts @@ -1,7 +1,7 @@ export interface ShortestConfig { headless: boolean; baseUrl: string; - testDir: string | string[]; + testPattern: string; anthropicKey: string; mailosaur?: { apiKey: string; diff --git a/shortest.config.ts b/shortest.config.ts index 3438a79c..eace1e16 100644 --- a/shortest.config.ts +++ b/shortest.config.ts @@ -3,7 +3,7 @@ import type { ShortestConfig } from "@antiwork/shortest"; export default { headless: false, baseUrl: "http://localhost:3000", - testDir: ["app/__tests__", "examples"], + testPattern: "**/*.test.ts", anthropicKey: process.env.ANTHROPIC_API_KEY, mailosaur: { apiKey: process.env.MAILOSAUR_API_KEY,