{"id":51646477,"url":"https://github.com/zerodrop-dev/better-auth-playwright-zerodrop","last_synced_at":"2026-07-13T23:02:41.156Z","repository":{"id":368049150,"uuid":"1283297526","full_name":"zerodrop-dev/better-auth-playwright-zerodrop","owner":"zerodrop-dev","description":"Testing Better Auth email verification, magic links, OTP and password reset with Playwright and ZeroDrop — no Docker, no regex, no shared inboxes","archived":false,"fork":false,"pushed_at":"2026-06-28T20:21:12.000Z","size":17,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-28T22:07:49.926Z","etag":null,"topics":["better-auth","email-testing","magic-link","otp","playwright","testing","typescript","zerodrop"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zerodrop-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-28T19:11:29.000Z","updated_at":"2026-06-28T20:21:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zerodrop-dev/better-auth-playwright-zerodrop","commit_stats":null,"previous_names":["zerodrop-dev/better-auth-playwright-zerodrop"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/zerodrop-dev/better-auth-playwright-zerodrop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerodrop-dev%2Fbetter-auth-playwright-zerodrop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerodrop-dev%2Fbetter-auth-playwright-zerodrop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerodrop-dev%2Fbetter-auth-playwright-zerodrop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerodrop-dev%2Fbetter-auth-playwright-zerodrop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zerodrop-dev","download_url":"https://codeload.github.com/zerodrop-dev/better-auth-playwright-zerodrop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerodrop-dev%2Fbetter-auth-playwright-zerodrop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35439213,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-13T02:00:06.543Z","response_time":119,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["better-auth","email-testing","magic-link","otp","playwright","testing","typescript","zerodrop"],"created_at":"2026-07-13T23:02:40.464Z","updated_at":"2026-07-13T23:02:41.140Z","avatar_url":"https://github.com/zerodrop-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# better-auth-playwright-zerodrop\n\n[![CI](https://github.com/zerodrop-dev/better-auth-playwright-zerodrop/actions/workflows/test.yml/badge.svg)](https://github.com/zerodrop-dev/better-auth-playwright-zerodrop/actions/workflows/test.yml)\n[![zerodrop-client](https://img.shields.io/npm/v/zerodrop-client.svg?label=zerodrop-client)](https://www.npmjs.com/package/zerodrop-client)\n[![better-auth](https://img.shields.io/npm/v/better-auth.svg?label=better-auth)](https://www.npmjs.com/package/better-auth)\n\n\u003e Testing Better Auth email flows with Playwright and ZeroDrop — no Docker, no regex, no shared inboxes.\n\nCovers all four email flows Better Auth supports — end to end, in CI, with real emails.\n\n```bash\ngit clone https://github.com/zerodrop-dev/better-auth-playwright-zerodrop\ncd better-auth-playwright-zerodrop\npnpm install\ncp .env.example .env   # add BETTER_AUTH_SECRET + RESEND_API_KEY\npnpm prisma migrate dev\npnpm test\n```\n\n## What this tests\n\n| Test file | Better Auth feature | ZeroDrop field |\n|---|---|---|\n| `email-verification.spec.ts` | `emailVerification` | `email.magicLink` |\n| `magic-link.spec.ts` | `magicLink` plugin | `email.magicLink` |\n| `email-otp.spec.ts` | `emailOTP` plugin | `email.otp` |\n| `password-reset.spec.ts` | `sendResetPassword` | `email.magicLink` |\n\n## How it works\n\nBetter Auth sends real emails via Resend. ZeroDrop catches them at Cloudflare's edge and auto-extracts OTPs and magic links before your test reads them.\n\n```typescript\n// Generate a unique inbox per test — no network request\nconst inbox = mail.generateInbox();\n\n// Trigger the email flow in your app...\nawait page.fill('[name=\"email\"]', inbox);\nawait page.click('[type=\"submit\"]');\n\n// ZeroDrop catches the email in \u003c1s\nconst email = await mail.waitForLatest(inbox, { timeout: 15000 });\n\nemail.otp        // \"847291\" — auto-extracted, no regex\nemail.magicLink  // \"https://...\" — auto-extracted, no HTML parsing\n```\n\nNo regex. No HTML parsing. No shared inboxes. No Docker.\n\n## Project structure\n\n```\nbetter-auth-playwright-zerodrop/\n├── app/\n│   ├── api/auth/[...all]/\n│   │   └── route.ts          # Better Auth API handler\n│   ├── lib/\n│   │   ├── auth.ts           # Better Auth server config\n│   │   └── auth-client.ts    # Better Auth client config\n│   ├── signup/page.tsx       # Sign up page\n│   ├── login/page.tsx        # Login (password, magic link, OTP)\n│   ├── dashboard/page.tsx    # Protected dashboard\n│   ├── forgot-password/      # Password reset request\n│   └── reset-password/       # Password reset form\n├── tests/\n│   ├── email-verification.spec.ts\n│   ├── magic-link.spec.ts\n│   ├── email-otp.spec.ts\n│   └── password-reset.spec.ts\n├── prisma/\n│   └── schema.prisma         # User, Session, Account, Verification\n├── playwright.config.ts\n├── package.json\n└── .env.example\n```\n\n## Stack\n\n| Tool | Purpose |\n|---|---|\n| [Better Auth](https://better-auth.com) | Authentication framework |\n| [Resend](https://resend.com) | Email sending |\n| [ZeroDrop](https://zerodrop.dev) | Email catching + OTP/magic link extraction |\n| [Playwright](https://playwright.dev) | E2E testing |\n| [Next.js 15](https://nextjs.org) | App framework |\n| [Prisma + SQLite](https://prisma.io) | Database (swap for Postgres in production) |\n\n## Setup\n\n**1. Clone and install**\n\n```bash\ngit clone https://github.com/zerodrop-dev/better-auth-playwright-zerodrop\ncd better-auth-playwright-zerodrop\npnpm install\n```\n\n**2. Configure environment**\n\n```bash\ncp .env.example .env\n```\n\n| Variable | Where to get it |\n|---|---|\n| `BETTER_AUTH_SECRET` | `openssl rand -base64 32` |\n| `RESEND_API_KEY` | [resend.com](https://resend.com) → API Keys |\n| `DATABASE_URL` | `file:./dev.db` (SQLite, already set) |\n\n**3. Set up the database**\n\n```bash\npnpm prisma migrate dev\n```\n\n**4. Run the app**\n\n```bash\npnpm dev\n```\n\n**5. Run tests**\n\n```bash\npnpm test\n```\n\n## GitHub Actions CI\n\nNo Docker. No SMTP service. ZeroDrop works out of the box.\n\n```yaml\n- uses: actions/checkout@v4\n- run: pnpm install\n- run: pnpm prisma migrate deploy\n- run: pnpm exec playwright install --with-deps chromium\n- run: pnpm test\nenv:\n  BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }}\n  RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}\n  DATABASE_URL: file:./test.db\n```\n\n## Why ZeroDrop\n\nEvery Better Auth email flow sends a real email. Without a way to catch and read that email, you can't test the full flow.\n\nThe common workarounds:\n\n| Approach | Problem |\n|---|---|\n| Mock the email | Tests pass while broken emails ship to production |\n| Shared Gmail inbox | Race conditions in parallel test runs |\n| MailHog | Requires Docker, doesn't test your real email provider |\n\nZeroDrop gives each test a real isolated inbox. OTPs and magic links are extracted at Cloudflare's edge — your test just reads `email.otp` or `email.magicLink`.\n\nFree, no signup required → [zerodrop.dev](https://zerodrop.dev)\n\n## Related\n\n- [ZeroDrop docs](https://docs.zerodrop.dev)\n- [Better Auth docs](https://better-auth.com/docs)\n- [Better Auth email OTP plugin](https://better-auth.com/docs/plugins/email-otp)\n- [Better Auth magic link plugin](https://better-auth.com/docs/plugins/magic-link)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzerodrop-dev%2Fbetter-auth-playwright-zerodrop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzerodrop-dev%2Fbetter-auth-playwright-zerodrop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzerodrop-dev%2Fbetter-auth-playwright-zerodrop/lists"}