From 67c5c4f34dbe73656169e5f110f880d75e26087b Mon Sep 17 00:00:00 2001 From: Peter Cruckshank Date: Thu, 31 Oct 2024 19:19:00 -0400 Subject: [PATCH 1/5] feat: UI tests for username change on /settings --- e2e/settings.spec.ts | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/e2e/settings.spec.ts b/e2e/settings.spec.ts index f53480c0..bdfdaa5b 100644 --- a/e2e/settings.spec.ts +++ b/e2e/settings.spec.ts @@ -1,4 +1,4 @@ -import test from "@playwright/test"; +import { test, expect } from "@playwright/test"; import { loggedInAsUserOne } from "./utils"; test.describe("Unauthenticated setttings Page", () => { @@ -10,6 +10,32 @@ test.describe("Authenticated settings Page", () => { test.beforeEach(async ({ page }) => { await loggedInAsUserOne(page); }); - // - // Replace with tests for authenticated users + + // Test for changing username + test('Username input field', async ({ page }) => { + await page.goto('http://localhost:3000/settings', { timeout: 30000 }); + + // Wait for the username input field to be visible + await page.locator('input[id="username"]').waitFor(); + + // Test that the input field is visible and has the correct attributes + const inputField = page.locator('input[id="username"]'); + await expect(inputField).toBeVisible(); + await expect(inputField).toHaveAttribute('type', 'text'); + await expect(inputField).toHaveAttribute('autocomplete', 'username'); + + // Test that the error message appears when the input field is invalid + await inputField.fill('45&p^x#@!96%*()'); + await page.locator('button[type="submit"]').click(); + const errorMessage = page.locator('p:text-is("Username can only contain alphanumerics and dashes.")') + await expect(errorMessage).toBeVisible(); + await expect(errorMessage).toHaveText('Username can only contain alphanumerics and dashes.'); + // Reset the form + await page.locator('button:has-text("Reset")').click(); + + // Test that the input field can be filled with a valid value and saves it + await inputField.fill('codu-rules'); + await page.locator('button[type="submit"]').click(); + await expect(inputField).toHaveValue('codu-rules'); + }); }); From 01c19f8e708047a272e6bf5c8e45ce49df3691fe Mon Sep 17 00:00:00 2001 From: Peter Cruckshank Date: Thu, 7 Nov 2024 14:54:03 -0500 Subject: [PATCH 2/5] fix: without adding "https://" a form error prevents /settings testing. --- e2e/setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/setup.ts b/e2e/setup.ts index 36382a62..869200e6 100644 --- a/e2e/setup.ts +++ b/e2e/setup.ts @@ -120,7 +120,7 @@ export const setup = async () => { image: `https://robohash.org/${encodeURIComponent(name)}?bgset=bg1`, location: "Ireland", bio: "Hi I am an robot", - websiteUrl: "codu.co", + websiteUrl: "https://codu.co", }; const [createdUser] = await db.insert(user).values(userData).returning(); return createdUser; From 071f93a0d6383b9c940ea7e15584f238481ed079 Mon Sep 17 00:00:00 2001 From: Peter Cruckshank Date: Thu, 7 Nov 2024 14:54:43 -0500 Subject: [PATCH 3/5] feat: add class names to use with UI testing. --- app/(app)/settings/_client.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/(app)/settings/_client.tsx b/app/(app)/settings/_client.tsx index 04d02cce..7bb24007 100644 --- a/app/(app)/settings/_client.tsx +++ b/app/(app)/settings/_client.tsx @@ -86,10 +86,12 @@ const Settings = ({ profile }: { profile: User }) => { useEffect(() => { if (isSuccess) { - toast.success("Saved"); + toast.success("Saved", { className: "toast-success" }); } if (isError) { - toast.error("Something went wrong saving settings."); + toast.error("Something went wrong saving settings.", { + className: "toast-error", + }); } }, [isError, isSuccess]); From f9140cfe94fd66a732c808732cc8d49816d90512 Mon Sep 17 00:00:00 2001 From: Peter Cruckshank Date: Thu, 7 Nov 2024 14:55:23 -0500 Subject: [PATCH 4/5] feat: new tests to check for toast message and field change after reset. --- e2e/settings.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/e2e/settings.spec.ts b/e2e/settings.spec.ts index bdfdaa5b..b0c39b03 100644 --- a/e2e/settings.spec.ts +++ b/e2e/settings.spec.ts @@ -36,6 +36,12 @@ test.describe("Authenticated settings Page", () => { // Test that the input field can be filled with a valid value and saves it await inputField.fill('codu-rules'); await page.locator('button[type="submit"]').click(); + const toastError = page.locator('.toast-success'); + await expect(toastError).toBeVisible(); + await expect(toastError).toBeHidden(); + + // Reload the page and check that the input field has the correct value + await page.reload(); await expect(inputField).toHaveValue('codu-rules'); }); }); From fcd1dbb533031a6c932053c1d9e7d273c63453b3 Mon Sep 17 00:00:00 2001 From: Peter Cruckshank Date: Sat, 9 Nov 2024 10:50:42 -0500 Subject: [PATCH 5/5] fix: added tests for min and max username values and error messages. --- e2e/settings.spec.ts | 60 ++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/e2e/settings.spec.ts b/e2e/settings.spec.ts index b0c39b03..3f29626f 100644 --- a/e2e/settings.spec.ts +++ b/e2e/settings.spec.ts @@ -10,38 +10,56 @@ test.describe("Authenticated settings Page", () => { test.beforeEach(async ({ page }) => { await loggedInAsUserOne(page); }); - + // Test for changing username - test('Username input field', async ({ page }) => { - await page.goto('http://localhost:3000/settings', { timeout: 30000 }); - - // Wait for the username input field to be visible - await page.locator('input[id="username"]').waitFor(); - - // Test that the input field is visible and has the correct attributes + test("Username input field", async ({ page }) => { + await page.goto("http://localhost:3000/settings", { timeout: 30000 }); + const inputField = page.locator('input[id="username"]'); + const submitButton = page.locator('button[type="submit"]'); + + // Test that the input field is visible and has the correct attributes await expect(inputField).toBeVisible(); - await expect(inputField).toHaveAttribute('type', 'text'); - await expect(inputField).toHaveAttribute('autocomplete', 'username'); - + await expect(inputField).toHaveAttribute("type", "text"); + await expect(inputField).toHaveAttribute("autocomplete", "username"); + // Test that the error message appears when the input field is invalid - await inputField.fill('45&p^x#@!96%*()'); - await page.locator('button[type="submit"]').click(); - const errorMessage = page.locator('p:text-is("Username can only contain alphanumerics and dashes.")') + await inputField.fill("45&p^x#@!96%*()"); + await submitButton.click(); + const errorMessage = page.locator( + 'p:text-is("Username can only contain alphanumerics and dashes.")', + ); await expect(errorMessage).toBeVisible(); - await expect(errorMessage).toHaveText('Username can only contain alphanumerics and dashes.'); - // Reset the form + await expect(errorMessage).toHaveText( + "Username can only contain alphanumerics and dashes.", + ); + + // Test minimum length + await inputField.fill("ab"); + await submitButton.click(); + await expect( + page.locator('p:text-is("String must contain at least 3 character(s)")'), + ).toBeVisible(); + + // Test maximum length + await inputField.fill("a".repeat(51)); + await submitButton.click(); + await expect( + page.locator('p:text-is("Max username length is 40 characters.")'), + ).toBeVisible(); + + // Reset the form await page.locator('button:has-text("Reset")').click(); - + // Test that the input field can be filled with a valid value and saves it - await inputField.fill('codu-rules'); - await page.locator('button[type="submit"]').click(); - const toastError = page.locator('.toast-success'); + await inputField.fill("codu-rules"); + await page.locator('button[type="submit"]').click(); + const toastError = page.locator(".toast-success"); await expect(toastError).toBeVisible(); await expect(toastError).toBeHidden(); // Reload the page and check that the input field has the correct value await page.reload(); - await expect(inputField).toHaveValue('codu-rules'); + await expect(inputField).toHaveValue("codu-rules"); }); });