diff --git a/.github/workflows/ci-frontend-e2e.yml b/.github/workflows/ci-frontend-e2e.yml index a824d8e9d..17af0ca4a 100644 --- a/.github/workflows/ci-frontend-e2e.yml +++ b/.github/workflows/ci-frontend-e2e.yml @@ -59,6 +59,8 @@ jobs: run: | sed -En '/API_JWT_PUBLIC_KEY/,/-----END PUBLIC KEY-----/p' ../api/override.env >> .env.local cat .env.development >> .env.local + # Use the localhost url for tests + sed -i 's|^SENDY_API_URL=.*|SENDY_API_URL=http://localhost:3000|' .env.local npm run build -- --no-lint - name: Run e2e tests (Shard ${{ matrix.shard }}/${{ matrix.total_shards }}) diff --git a/frontend/next.config.js b/frontend/next.config.js index d87cf3b74..11df24df8 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -101,6 +101,9 @@ const nextConfig = { "types", ], }, + experimental: { + testProxy: true, + }, }; module.exports = withNextIntl(nextConfig); diff --git a/frontend/tests/e2e/subscribe.spec.ts b/frontend/tests/e2e/subscribe.spec.ts new file mode 100644 index 000000000..f51ad992c --- /dev/null +++ b/frontend/tests/e2e/subscribe.spec.ts @@ -0,0 +1,69 @@ +/* eslint-disable testing-library/prefer-screen-queries */ + +import { + expect, + NextFixture, + test, +} from "next/experimental/testmode/playwright"; + +function mockAPIEndpoints(next: NextFixture, responseText = "1") { + next.onFetch((request: Request) => { + if (request.url.endsWith("/subscribe") && request.method === "POST") { + return new Response(responseText, { + status: 200, + headers: { + "Content-Type": "text/plain", + }, + }); + } + + return "abort"; + }); +} +test.beforeEach(async ({ page }) => { + await page.goto("/subscribe"); +}); + +test.afterEach(async ({ context }) => { + await context.close(); +}); + +test("has title", async ({ page }) => { + await expect(page).toHaveTitle(/Subscribe | Simpler.Grants.gov/); +}); + +test("client side errors", async ({ page }) => { + await page.getByRole("button", { name: /subscribe/i }).click(); + + // Verify client-side errors for required fields + await expect(page.getByTestId("errorMessage")).toHaveCount(2); + await expect(page.getByText("Please enter a name.")).toBeVisible(); + await expect(page.getByText("Please enter an email address.")).toBeVisible(); +}); + +test("successful signup", async ({ next, page }) => { + mockAPIEndpoints(next); + + await page.getByLabel("First Name (required)").fill("Apple"); + await page.getByLabel("Email (required)").fill("name@example.com"); + + await page.getByRole("button", { name: /subscribe/i }).click(); + + await expect( + page.getByRole("heading", { name: /you['’]re subscribed/i }), + ).toBeVisible(); +}); + +test("error during signup", async ({ next, page }) => { + mockAPIEndpoints(next, "Error with subscribing"); + + await page.getByLabel("First Name (required)").fill("Apple"); + await page.getByLabel("Email (required)").fill("name@example.com"); + + await page.getByRole("button", { name: /subscribe/i }).click(); + + await expect(page.getByTestId("errorMessage")).toHaveCount(1); + await expect( + page.getByText(/an error occurred when trying to save your subscription./i), + ).toBeVisible(); +});