diff --git a/DEMO.md b/DEMO.md new file mode 100644 index 0000000..4de07e0 --- /dev/null +++ b/DEMO.md @@ -0,0 +1,36 @@ +Prompt 1: + +You're testing a web app by hand, using your browser tool. Don't write any code. + +App: https://deploy-preview-10--endform-playwright-tutorial.netlify.app + +1. Go to `/sign-up` and create an account with a made-up email like `demo-@example.com` and the password `testpassword123`. +2. On the Team Settings page (`/dashboard`), invite a teammate using another made-up email, with the Member role, and wait for "Invitation sent successfully". +3. Open the Activity page from the sidebar. +4. Check that the newest (top) entry says "You invited a team member". + +Report PASS or FAIL. Describe exactly what you saw at each step, including the full list of entries on the Activity page. + +Prompt 2: + +In this repo (branch `demo/invite-activity-after-response`), write a new Playwright test at `tests/team-invite-activity.live.spec.ts`. Explore the app first, using existing tests and functionality through an endform live test. + +- Start a session inside an existing test that already has a logged-in new user: `tests/duplicate-invite.spec.ts` or similar using endform live test. +- Step through the scenario one action at a time. To expore and figure out which playwright code makes sense for the test. + - invite a teammate from the Team Settings page (`/dashboard`); + - wait for "Invitation sent successfully"; + - open the Activity page from the sidebar; + - check that the newest entry is "You invited a team member". +- Once every step has worked live, stop the session and create a nice new playwright test for this flow. +- Follow the suite's conventions: the `testWithNewUser` fixture from `tests/test-with-new-user.ts`, `test.step` blocks, role-based locators, and a unique invite email per run. +- Finish by running it once with `npx endform test team-invite-activity.live`. + +Next commands: + +p playwright test team-invite-activity --debug --no-deps + +p endform test team-invite-activity --repeat-each=100 --no-deps + +Then ask: + +look at `team-invite-activity` playwright/endform runs from the last hour. What's the pass rate, and what's the most common failure? Is it a bug in the app or noise in the test? diff --git a/app/(login)/actions.ts b/app/(login)/actions.ts index f22b1cf..41f9906 100644 --- a/app/(login)/actions.ts +++ b/app/(login)/actions.ts @@ -3,6 +3,7 @@ import { and, eq } from "drizzle-orm"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; +import { after } from "next/server"; import { z } from "zod"; import { logActivity } from "@/lib/auth/activity"; import { signup } from "@/lib/auth/login"; @@ -22,6 +23,7 @@ import { type User, users, } from "@/lib/db/schema"; +import { sendInvitationEmail } from "@/lib/email"; import { isFaultActive } from "@/lib/faults"; const signInSchema = z.object({ @@ -365,14 +367,13 @@ export const inviteTeamMember = validatedActionWithUser( }) .returning(); - await logActivity( - userWithTeam.teamId, - user.id, - ActivityType.INVITE_TEAM_MEMBER, - ); - - // TODO: Send invitation email and include ?inviteId={id} to sign-up URL - // await sendInvitationEmail(email, userWithTeam.team.name, role) + // Email the invitee and log the invite once the response has been sent, + // so inviting feels instant. + const teamId = userWithTeam.teamId; + after(async () => { + await sendInvitationEmail(email, role); + await logActivity(teamId, user.id, ActivityType.INVITE_TEAM_MEMBER); + }); return { success: "Invitation sent successfully", id: invitation[0].id }; }, diff --git a/endform.config.ts b/endform.config.ts new file mode 100644 index 0000000..d087c33 --- /dev/null +++ b/endform.config.ts @@ -0,0 +1,5 @@ +import { defineEndformConfig } from "endform"; + +export default defineEndformConfig({ + organizationId: "68prmZ74", +}); diff --git a/lib/email.ts b/lib/email.ts new file mode 100644 index 0000000..fc7dc8a --- /dev/null +++ b/lib/email.ts @@ -0,0 +1,14 @@ +import "server-only"; + +// Stand-in for a transactional email provider. Most sends are quick but, like +// most third-party APIs, it has a slow tail. +export async function sendInvitationEmail(email: string, role: string) { + const latencyMs = + Math.random() < 0.15 + ? 6000 + Math.random() * 3000 + : 50 + Math.random() * 100; + await new Promise((resolve) => setTimeout(resolve, latencyMs)); + console.log( + `[email] sent ${role} invitation to ${email} in ${Math.round(latencyMs)}ms`, + ); +} diff --git a/playwright.config.ts b/playwright.config.ts index 4b54bbc..5b1f26f 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,7 +10,8 @@ import type { PlaywrightOpentelemetryUseOptions } from "playwright-opentelemetry // dotenv.config({ path: path.resolve(__dirname, '.env') }); export const baseURL = - process.env.BASE_URL || "https://endform-playwright-tutorial.vercel.app"; + process.env.BASE_URL || + "https://deploy-preview-10--endform-playwright-tutorial.netlify.app"; const playwrightOtelEnabled = Boolean( process.env.PLAYWRIGHT_TRACE_API_ENDPOINT || @@ -47,7 +48,9 @@ export default defineConfig({ // baseURL: "http://localhost:3000", /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: playwrightOtelEnabled ? "on" : "retain-on-failure", + // trace: playwrightOtelEnabled ? "on" : "retain-on-failure", + trace: "on", + // trace: "retain-on-failure", playwrightOpentelemetry: playwrightOtelEnabled ? { trace: "on",