From 01906384f9f4046c1f031d1b9712ec7993fea9d9 Mon Sep 17 00:00:00 2001 From: Toti Date: Mon, 15 Jun 2026 07:59:34 -0300 Subject: [PATCH 1/2] chore: remove stray recording exports and gitignore them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two generator export artifacts (humanjs-recording.ts at the root and in examples/) plus their demo:recorder / recorder scripts were swept into the generator branch by a stray git add -A. They point at a hardcoded, brittle eventurex.com.ar recording — not real demos. Remove them and gitignore the generator's default export filenames so future exports aren't re-committed. --- .gitignore | 4 ++++ examples/humanjs-recording.ts | 34 ---------------------------------- examples/package.json | 3 +-- humanjs-recording.ts | 26 -------------------------- package.json | 3 +-- 5 files changed, 6 insertions(+), 64 deletions(-) delete mode 100644 examples/humanjs-recording.ts delete mode 100644 humanjs-recording.ts diff --git a/.gitignore b/.gitignore index ff0516a..4b5fbc9 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,10 @@ test-results # Demo recording output recordings +# @humanjs/generator default exports (throwaway recordings) +humanjs-recording.ts +humanjs-recording.spec.ts + # Environment .env .env.local diff --git a/examples/humanjs-recording.ts b/examples/humanjs-recording.ts deleted file mode 100644 index 959d2cf..0000000 --- a/examples/humanjs-recording.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { chromium, createHuman } from '@humanjs/playwright'; - -async function main() { - const browser = await chromium.launch({ headless: false }); - const page = await browser.newPage({ - viewport: { width: 1920, height: 1080 }, - }); - const human = await createHuman(page, { - personality: 'careful', - speed: 'human', - }); - - await human.goto('https://www.eventurex.com.ar/'); - await human.sleep(1000); - await human.click('role=link[name="Eventos"]'); - // await human.goto('https://www.eventurex.com.ar/eventos'); - console.log('hola'); - await human.click('div:nth-of-type(4) > div > div:nth-of-type(1) > a'); - - console.log('chau'); - - // await human.goto('https://www.eventurex.com.ar/eventos/medico-a-palos-1775827780992'); - await human.click('role=link[name="Comprar entradas"]'); - // await human.goto('https://www.eventurex.com.ar/eventos/medico-a-palos-1775827780992/comprar'); - await human.sleep(1000); - await human.click('div:nth-of-type(3) > button'); - await human.click('div:nth-of-type(3) > button'); - await human.scroll({ to: 239 }); - await human.click('role=button[name="Continuar"]'); - - await browser.close(); -} - -main(); diff --git a/examples/package.json b/examples/package.json index 758734d..8d512ba 100644 --- a/examples/package.json +++ b/examples/package.json @@ -14,8 +14,7 @@ "record": "tsx record-demo.ts", "record-manual": "tsx record-manual-demo.ts", "scroll": "tsx scroll-demo.ts", - "type": "tsx type-demo.ts", - "recorder": "tsx humanjs-recording.ts" + "type": "tsx type-demo.ts" }, "dependencies": { "@humanjs/playwright": "workspace:*", diff --git a/humanjs-recording.ts b/humanjs-recording.ts deleted file mode 100644 index 0477494..0000000 --- a/humanjs-recording.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { chromium, createHuman } from '@humanjs/playwright'; - -async function main() { - const browser = await chromium.launch({ headless: false }); - const page = await browser.newPage(); - const human = await createHuman(page, { - personality: 'careful', - speed: 'human', - }); - - await human.goto('https://www.eventurex.com.ar/'); - await human.click('role=link[name="Eventos"]'); - await human.goto('https://www.eventurex.com.ar/eventos'); - await human.click('div:nth-of-type(4) > div > div:nth-of-type(1) > a'); - await human.goto('https://www.eventurex.com.ar/eventos/medico-a-palos-1775827780992'); - await human.click('role=link[name="Comprar entradas"]'); - await human.goto('https://www.eventurex.com.ar/eventos/medico-a-palos-1775827780992/comprar'); - await human.click('div:nth-of-type(3) > button'); - await human.click('div:nth-of-type(3) > button'); - await human.scroll({ to: 239 }); - await human.click('role=button[name="Continuar"]'); - - await browser.close(); -} - -main(); diff --git a/package.json b/package.json index b87b881..69462ef 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,7 @@ "demo:record": "turbo run build --filter=@humanjs/recorder... && pnpm --filter @humanjs/examples record", "demo:record-manual": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples record-manual", "demo:scroll": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples scroll", - "demo:type": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples type", - "demo:recorder": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples recorder" + "demo:type": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples type" }, "commitlint": { "extends": [ From 13f5d593ed4d58f30d34ca9c44716eae508f9ddb Mon Sep 17 00:00:00 2001 From: Toti Date: Mon, 15 Jun 2026 08:06:10 -0300 Subject: [PATCH 2/2] feat(examples): add a generator demo that prints the generated test Replaces the removed brittle recorder script with a real, curated demo: records a clean sign-in flow (timeline-only) and runs the public generatePlaywrightTest / generateHumanJS codegen on it, printing the spec and standalone script the generator would export. Self-contained (setContent, headless), role-first selectors, password masking shown. Wired as `pnpm demo:generate`. --- examples/generate-demo.ts | 87 +++++++++++++++++++++++++++++++++++++++ examples/package.json | 3 +- package.json | 3 +- 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 examples/generate-demo.ts diff --git a/examples/generate-demo.ts b/examples/generate-demo.ts new file mode 100644 index 0000000..091dbe7 --- /dev/null +++ b/examples/generate-demo.ts @@ -0,0 +1,87 @@ +/** + * HumanJS generator demo — record a clean flow, then print the test the + * generator would produce. + * + * The visual generator (`npx @humanjs/generator `) captures your clicks in + * a real browser and exports a humanized `@playwright/test` spec. This demo + * shows the engine behind that export, headless and offline: it records a short + * session, then runs the public codegen (`generatePlaywrightTest` / + * `generateHumanJS`) on the timeline and prints both a spec and a standalone + * script. + * + * Run with: + * pnpm demo:generate + * PERSONALITY=distracted pnpm demo:generate (changes the generated humanOptions) + */ + +import { + chromium, + createHuman, + generateHumanJS, + generatePlaywrightTest, +} from '@humanjs/playwright'; +import { parsePersonality } from './lib'; + +const DEMO_HTML = /* html */ ` + + + + + Sign in + + +

Sign in

+ + + + + +`; + +function banner(title: string): void { + const rule = '─'.repeat(64); + console.log(`\n${rule}\n ${title}\n${rule}`); +} + +async function main() { + const personality = parsePersonality(process.env.PERSONALITY, 'careful', 'PERSONALITY'); + + // Headless — this demo is about the generated code, not a visible run. + const browser = await chromium.launch({ headless: true }); + try { + const page = await browser.newPage(); + await page.setContent(DEMO_HTML); + const human = await createHuman(page, { personality, seed: 'generate-demo' }); + + // Timeline-only recording (`video: false`) — no frame capture or ffmpeg. + // We only want the action log to feed the codegen, exactly like the + // generator's export does. Selectors are role-first, with a CSS fallback + // for the password field (password inputs expose no `textbox` role). + const rec = await human.record({ name: 'sign in', video: false }, async () => { + await human.type('role=textbox[name="Email"]', 'demo@humanjs.dev'); + await human.type('#password', 'hunter2'); // password input → value is masked + await human.click('role=button[name="Continue"]'); + }); + + // The same public codegen the generator runs on a curated timeline. The + // spec uses the `@humanjs/playwright/test` fixture (instant in CI); the + // standalone script drives a `createHuman` session directly. + banner('generatePlaywrightTest(timeline) → sign-in.spec.ts'); + console.log(generatePlaywrightTest(rec.timeline)); + + banner('generateHumanJS(timeline) → sign-in.ts'); + console.log(generateHumanJS(rec.timeline)); + + console.log( + `\nCaptured ${rec.timeline.events.length} actions — this is what "npx @humanjs/generator " exports, minus the visual editor.`, + ); + console.log('The password value is masked; edit the export to read it from process.env.'); + } finally { + await browser.close(); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/examples/package.json b/examples/package.json index 8d512ba..506e71f 100644 --- a/examples/package.json +++ b/examples/package.json @@ -14,7 +14,8 @@ "record": "tsx record-demo.ts", "record-manual": "tsx record-manual-demo.ts", "scroll": "tsx scroll-demo.ts", - "type": "tsx type-demo.ts" + "type": "tsx type-demo.ts", + "generate": "tsx generate-demo.ts" }, "dependencies": { "@humanjs/playwright": "workspace:*", diff --git a/package.json b/package.json index 69462ef..e0de4a5 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "demo:record": "turbo run build --filter=@humanjs/recorder... && pnpm --filter @humanjs/examples record", "demo:record-manual": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples record-manual", "demo:scroll": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples scroll", - "demo:type": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples type" + "demo:type": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples type", + "demo:generate": "turbo run build --filter=@humanjs/playwright... && pnpm --filter @humanjs/examples generate" }, "commitlint": { "extends": [