From 5b3ab3fae9a4c3149117dd7b840b7662f2794a8d Mon Sep 17 00:00:00 2001 From: ztest95 <110767420+ztest95@users.noreply.github.com> Date: Tue, 30 Sep 2025 18:10:54 +0800 Subject: [PATCH 1/5] feat: authentication tests --- package-lock.json | 8 +-- package.json | 2 +- tests/auth.spec.ts | 122 ++++++++++++++++++++++++++++++++++++++++++ tests/example.spec.ts | 4 +- 4 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 tests/auth.spec.ts diff --git a/package-lock.json b/package-lock.json index 5895cf8..2fb363c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "dotenv": "^17.2.1" + "dotenv": "^17.2.3" }, "devDependencies": { "@playwright/test": "^1.55.0", @@ -43,9 +43,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" diff --git a/package.json b/package.json index 3acebe3..223d70c 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,6 @@ "@types/node": "^24.3.0" }, "dependencies": { - "dotenv": "^17.2.1" + "dotenv": "^17.2.3" } } diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts new file mode 100644 index 0000000..18c79c3 --- /dev/null +++ b/tests/auth.spec.ts @@ -0,0 +1,122 @@ +import { test, expect } from '@playwright/test'; +import crypto from 'crypto'; + +// Localize environment variables +const TEST_USER_NAME = process.env.TEST_USER_NAME; +const TEST_USER_EMAIL = process.env.TEST_USER_EMAIL; +const TEST_USER_PASSWORD = process.env.TEST_USER_PASSWORD; +const TEST_ADMIN_EMAIL = process.env.TEST_ADMIN_EMAIL; +const TEST_ADMIN_PASSWORD = process.env.TEST_ADMIN_PASSWORD; +const TEST_LAWYER_EMAIL = process.env.TEST_LAWYER_EMAIL; +const TEST_LAWYER_PASSWORD = process.env.TEST_LAWYER_PASSWORD; +const TEST_CLIENT_EMAIL = process.env.TEST_CLIENT_EMAIL; +const TEST_CLIENT_PASSWORD = process.env.TEST_CLIENT_PASSWORD; + +// Check if required environment variables are set +if (!TEST_USER_NAME || !TEST_USER_EMAIL || !TEST_USER_PASSWORD) { + throw new Error('Missing required environment variables: TEST_USER_NAME, TEST_USER_EMAIL, TEST_USER_PASSWORD'); +} + +// Setup test - ensure test user exists for duplicate tests +test.beforeAll('setup: create test user if not exists', async ({ browser }) => { + const context = await browser.newContext(); + const page = await context.newPage(); + + try { + await page.goto('/register.php'); + + // Try to create the test user + await page.fill('input[name="name"]', TEST_USER_NAME); + await page.fill('input[name="email"]', TEST_USER_EMAIL); + await page.fill('input[name="password"]', TEST_USER_PASSWORD); + + await page.getByRole('button', { name: 'Create Account' }).click(); + + // Don't fail if user already exists - that's what we want + console.log('Test user setup completed (may already exist)'); + } catch (error) { + console.log('Test user setup: user might already exist'); + } finally { + await context.close(); + } +}); + +function generateUniqueUser() { + const uniqueId = `${Date.now()}-${crypto.randomBytes(4).toString('hex')}`; + return { + name: `TestUser-${uniqueId}`, + email: `test+${uniqueId}@example.com`, + password: 'Password123!' + }; +} + +test.describe("User Registration", () => { + + test('users can register with unique email', async ({ page }) => { + await page.goto('/register.php'); + + const user = generateUniqueUser(); + + // Fill in registration form with unique email + await page.fill('input[name="name"]', user.name); + await page.fill('input[name="email"]', user.email); + await page.fill('input[name="password"]', user.password); + await page.getByRole('button', { name: 'Create Account' }).click(); + + await expect(page).toHaveURL(/login/); + + // Comment: Lacks Success Response + }); + + test('users cannot register with duplicate name', async ({ page }) => { + await page.goto('/register.php'); + + const user = generateUniqueUser(); + + await page.fill('input[name="name"]', TEST_USER_NAME); + await page.fill('input[name="email"]', user.email); + await page.fill('input[name="password"]', user.password); + await page.getByRole('button', { name: 'Create Account' }).click(); + + await expect(page.locator('.alert-danger')).toContainText(/.*name is already used/i); + }); + + test('users cannot register with duplicate email', async ({ page }) => { + await page.goto('/register.php'); + + const user = generateUniqueUser(); + + await page.fill('input[name="name"]', user.name); + await page.fill('input[name="email"]', TEST_USER_EMAIL); + await page.fill('input[name="password"]', user.password); + await page.getByRole('button', { name: 'Create Account' }).click(); + + await expect(page.locator('.alert-danger')).toContainText(/email is already used/i); + }); +}) + +test.describe("User Login", () => { + + test('users can login with correct email and password', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_USER_EMAIL!); + await page.fill('input[name="password"]', TEST_USER_PASSWORD!); + await page.getByRole('button', { name: 'Login' }).click(); + + await expect(page).toHaveURL(/dashboard/); + }); + + test('users cannot login with incorrect email or password', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_USER_EMAIL!); + await page.fill('input[name="password"]', 'wrongpassword123'); + await page.getByRole('button', { name: 'Login' }).click(); + + await expect(page.locator('.alert-danger')).toContainText(/invalid.*credentials|incorrect.*email.*password|login.*failed/i); + + await expect(page).toHaveURL(/login/); + }); +}) + diff --git a/tests/example.spec.ts b/tests/example.spec.ts index 6f6cc6f..df01c6f 100644 --- a/tests/example.spec.ts +++ b/tests/example.spec.ts @@ -11,8 +11,8 @@ test('register page', async ({ page }) => { await page.goto('/login.php'); // Click the get started link. - await page.getByRole('link', { name: 'Create an account' }).click(); + await page.getByRole('link', { name: 'Create Account' }).click(); // Expects page to have a button with the name of Create Account. - await expect(page.getByRole('button', { name: 'Register' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Create Account' })).toBeVisible(); }); \ No newline at end of file From 1100d57786f384f95acd85c2761a418115c06848 Mon Sep 17 00:00:00 2001 From: ztest95 <110767420+ztest95@users.noreply.github.com> Date: Tue, 30 Sep 2025 20:47:59 +0800 Subject: [PATCH 2/5] feat: authorization / rbac tests --- tests/auth.spec.ts | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index 18c79c3..a7ff0cb 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -17,6 +17,18 @@ if (!TEST_USER_NAME || !TEST_USER_EMAIL || !TEST_USER_PASSWORD) { throw new Error('Missing required environment variables: TEST_USER_NAME, TEST_USER_EMAIL, TEST_USER_PASSWORD'); } +if (!TEST_ADMIN_EMAIL || !TEST_ADMIN_PASSWORD) { + throw new Error('Missing required environment variables: TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD'); +} + +if (!TEST_LAWYER_EMAIL || !TEST_LAWYER_PASSWORD) { + throw new Error('Missing required environment variables: TEST_LAWYER_EMAIL, TEST_LAWYER_PASSWORD'); +} + +if (!TEST_CLIENT_EMAIL || !TEST_CLIENT_PASSWORD) { + throw new Error('Missing required environment variables: TEST_CLIENT_EMAIL, TEST_CLIENT_PASSWORD'); +} + // Setup test - ensure test user exists for duplicate tests test.beforeAll('setup: create test user if not exists', async ({ browser }) => { const context = await browser.newContext(); @@ -115,8 +127,55 @@ test.describe("User Login", () => { await page.getByRole('button', { name: 'Login' }).click(); await expect(page.locator('.alert-danger')).toContainText(/invalid.*credentials|incorrect.*email.*password|login.*failed/i); + await expect(page).toHaveURL(/login/); + }); + test('several login attempts should warn / lockout user', async ({ page }) => { + await page.goto('/login.php'); + + for (let i = 0; i < 10; i++) { + await page.fill('input[name="email"]', TEST_USER_EMAIL!); + await page.fill('input[name="password"]', 'wrongpassword123'); + await page.getByRole('button', { name: 'Login' }).click(); + } + + await expect(page.locator('.alert-warning')).toContainText(/too many.*attempts|account.*locked|try again later/i); await expect(page).toHaveURL(/login/); }); }) +test.describe("Role Based Access Control", () => { + + test('admin users can access admin features', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_ADMIN_EMAIL); + await page.fill('input[name="password"]', TEST_ADMIN_PASSWORD); + await page.getByRole('button', { name: 'Login' }).click(); + + await expect(page).toHaveURL(/dashboard/); + await expect(page.locator('span.badge-role')).toHaveText(/Admin/i); + }); + + test('lawyers can access lawyer features', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_LAWYER_EMAIL); + await page.fill('input[name="password"]', TEST_LAWYER_PASSWORD); + await page.getByRole('button', { name: 'Login' }).click(); + + await expect(page).toHaveURL(/dashboard/); + await expect(page.locator('span.badge-role')).toHaveText(/Lawyer/i); + }); + + test('clients can access client features', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_CLIENT_EMAIL); + await page.fill('input[name="password"]', TEST_CLIENT_PASSWORD); + await page.getByRole('button', { name: 'Login' }).click(); + + await expect(page).toHaveURL(/dashboard/); + await expect(page.locator('span.badge-role')).toHaveText(/Client/i); + }); +}); From ac6c10af43da88901d6cec2e85a45a6889b62fd5 Mon Sep 17 00:00:00 2001 From: ztest95 <110767420+ztest95@users.noreply.github.com> Date: Wed, 1 Oct 2025 02:43:05 +0800 Subject: [PATCH 3/5] ci: add env to workflow & update env example --- .env.example | 15 ++++++++++++++- .github/workflows/playwright.yml | 9 +++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 52cf5a5..2fc90cb 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,14 @@ -WEBSITE_URL= \ No newline at end of file +WEBSITE_URL= + +TEST_USER_NAME= +TEST_USER_EMAIL= +TEST_USER_PASSWORD= + +TEST_ADMIN_EMAIL= +TEST_ADMIN_PASSWORD= + +TEST_LAWYER_EMAIL= +TEST_LAWYER_PASSWORD= + +TEST_CLIENT_EMAIL= +TEST_CLIENT_PASSWORD= \ No newline at end of file diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index b5b5749..1f1bf8a 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -10,6 +10,15 @@ jobs: runs-on: ubuntu-latest env: WEBSITE_URL: ${{ secrets.WEBSITE_URL }} + TEST_USER_NAME: ${{ secrets.TEST_USER_NAME }} + TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }} + TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }} + TEST_ADMIN_EMAIL: ${{ secrets.TEST_ADMIN_EMAIL }} + TEST_ADMIN_PASSWORD: ${{ secrets.TEST_ADMIN_PASSWORD }} + TEST_LAWYER_EMAIL: ${{ secrets.TEST_LAWYER_EMAIL }} + TEST_LAWYER_PASSWORD: ${{ secrets.TEST_LAWYER_PASSWORD }} + TEST_CLIENT_EMAIL: ${{ secrets.TEST_CLIENT_EMAIL }} + TEST_CLIENT_PASSWORD: ${{ secrets.TEST_CLIENT_PASSWORD }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 From fd16a02e87939a4b5c4766fdd8beebfca982b602 Mon Sep 17 00:00:00 2001 From: ztest95 <110767420+ztest95@users.noreply.github.com> Date: Mon, 20 Oct 2025 01:06:58 +0800 Subject: [PATCH 4/5] feat: update test cases - remove test cases as per new requirements - update tests due to website changes --- tests/auth.spec.ts | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index a7ff0cb..887a781 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -38,7 +38,8 @@ test.beforeAll('setup: create test user if not exists', async ({ browser }) => { await page.goto('/register.php'); // Try to create the test user - await page.fill('input[name="name"]', TEST_USER_NAME); + await page.fill('input[name="first_name"]', TEST_USER_NAME); + await page.fill('input[name="last_name"]', TEST_USER_NAME); await page.fill('input[name="email"]', TEST_USER_EMAIL); await page.fill('input[name="password"]', TEST_USER_PASSWORD); @@ -56,7 +57,8 @@ test.beforeAll('setup: create test user if not exists', async ({ browser }) => { function generateUniqueUser() { const uniqueId = `${Date.now()}-${crypto.randomBytes(4).toString('hex')}`; return { - name: `TestUser-${uniqueId}`, + first_name: `${uniqueId}`, + last_name: `TestUser`, email: `test+${uniqueId}@example.com`, password: 'Password123!' }; @@ -70,7 +72,8 @@ test.describe("User Registration", () => { const user = generateUniqueUser(); // Fill in registration form with unique email - await page.fill('input[name="name"]', user.name); + await page.fill('input[name="first_name"]', user.first_name); + await page.fill('input[name="last_name"]', user.last_name); await page.fill('input[name="email"]', user.email); await page.fill('input[name="password"]', user.password); await page.getByRole('button', { name: 'Create Account' }).click(); @@ -80,25 +83,13 @@ test.describe("User Registration", () => { // Comment: Lacks Success Response }); - test('users cannot register with duplicate name', async ({ page }) => { - await page.goto('/register.php'); - - const user = generateUniqueUser(); - - await page.fill('input[name="name"]', TEST_USER_NAME); - await page.fill('input[name="email"]', user.email); - await page.fill('input[name="password"]', user.password); - await page.getByRole('button', { name: 'Create Account' }).click(); - - await expect(page.locator('.alert-danger')).toContainText(/.*name is already used/i); - }); - test('users cannot register with duplicate email', async ({ page }) => { await page.goto('/register.php'); const user = generateUniqueUser(); - await page.fill('input[name="name"]', user.name); + await page.fill('input[name="first_name"]', user.first_name); + await page.fill('input[name="last_name"]', user.last_name); await page.fill('input[name="email"]', TEST_USER_EMAIL); await page.fill('input[name="password"]', user.password); await page.getByRole('button', { name: 'Create Account' }).click(); @@ -129,19 +120,6 @@ test.describe("User Login", () => { await expect(page.locator('.alert-danger')).toContainText(/invalid.*credentials|incorrect.*email.*password|login.*failed/i); await expect(page).toHaveURL(/login/); }); - - test('several login attempts should warn / lockout user', async ({ page }) => { - await page.goto('/login.php'); - - for (let i = 0; i < 10; i++) { - await page.fill('input[name="email"]', TEST_USER_EMAIL!); - await page.fill('input[name="password"]', 'wrongpassword123'); - await page.getByRole('button', { name: 'Login' }).click(); - } - - await expect(page.locator('.alert-warning')).toContainText(/too many.*attempts|account.*locked|try again later/i); - await expect(page).toHaveURL(/login/); - }); }) test.describe("Role Based Access Control", () => { From af73fa36c8af730525bfb97a452e09e643b8672d Mon Sep 17 00:00:00 2001 From: ztest95 <110767420+ztest95@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:26:40 +0800 Subject: [PATCH 5/5] feat: update auth tests & add auth setup --- .github/workflows/playwright.yml | 2 ++ playwright.config.ts | 5 ++++ tests/auth.setup.ts | 44 ++++++++++++++++++++++++++++ tests/auth.spec.ts | 50 ++++++++++++++++---------------- 4 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 tests/auth.setup.ts diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 1f1bf8a..fd8fe82 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -28,6 +28,8 @@ jobs: run: npm ci - name: Install Playwright Browsers run: npx playwright install --with-deps + - name: Run auth setup + run: npx playwright test tests/auth.setup.ts --project=setup - name: Run Playwright tests run: npx playwright test - uses: actions/upload-artifact@v4 diff --git a/playwright.config.ts b/playwright.config.ts index 870311b..0b66e0e 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -34,6 +34,11 @@ export default defineConfig({ /* Configure projects for major browsers */ projects: [ + { + name: 'setup', + testMatch: /.*\.setup\.ts/, + }, + { name: 'chromium', use: { ...devices['Desktop Chrome'] }, diff --git a/tests/auth.setup.ts b/tests/auth.setup.ts new file mode 100644 index 0000000..0132d11 --- /dev/null +++ b/tests/auth.setup.ts @@ -0,0 +1,44 @@ +import { test as setup, expect } from '@playwright/test'; + +const TEST_ADMIN_EMAIL = process.env.TEST_ADMIN_EMAIL; +const TEST_ADMIN_PASSWORD = process.env.TEST_ADMIN_PASSWORD; +const TEST_LAWYER_EMAIL = process.env.TEST_LAWYER_EMAIL; +const TEST_LAWYER_PASSWORD = process.env.TEST_LAWYER_PASSWORD; +const TEST_CLIENT_EMAIL = process.env.TEST_CLIENT_EMAIL; +const TEST_CLIENT_PASSWORD = process.env.TEST_CLIENT_PASSWORD; + +const adminFile = 'playwright/.auth/admin.json'; + +setup('authenticate as admin', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_ADMIN_EMAIL!); + await page.fill('input[name="password"]', TEST_ADMIN_PASSWORD!); + await page.getByRole('button', { name: 'Login Now' }).click(); + + await page.context().storageState({ path: adminFile }); +}); + +const clientFile = 'playwright/.auth/client.json'; + +setup('authenticate as client', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_CLIENT_EMAIL!); + await page.fill('input[name="password"]', TEST_CLIENT_PASSWORD!); + await page.getByRole('button', { name: 'Login Now' }).click(); + + await page.context().storageState({ path: clientFile }); +}); + +const lawyerFile = 'playwright/.auth/lawyer.json'; + +setup('authenticate as lawyer', async ({ page }) => { + await page.goto('/login.php'); + + await page.fill('input[name="email"]', TEST_LAWYER_EMAIL!); + await page.fill('input[name="password"]', TEST_LAWYER_PASSWORD!); + await page.getByRole('button', { name: 'Login Now' }).click(); + + await page.context().storageState({ path: lawyerFile }); +}); \ No newline at end of file diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index 887a781..96cdf5c 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -76,11 +76,10 @@ test.describe("User Registration", () => { await page.fill('input[name="last_name"]', user.last_name); await page.fill('input[name="email"]', user.email); await page.fill('input[name="password"]', user.password); + await page.fill('input[name="confirm_password"]', user.password); await page.getByRole('button', { name: 'Create Account' }).click(); await expect(page).toHaveURL(/login/); - - // Comment: Lacks Success Response }); test('users cannot register with duplicate email', async ({ page }) => { @@ -92,9 +91,10 @@ test.describe("User Registration", () => { await page.fill('input[name="last_name"]', user.last_name); await page.fill('input[name="email"]', TEST_USER_EMAIL); await page.fill('input[name="password"]', user.password); + await page.fill('input[name="confirm_password"]', user.password); await page.getByRole('button', { name: 'Create Account' }).click(); - await expect(page.locator('.alert-danger')).toContainText(/email is already used/i); + await expect(page.locator('.alert-danger')).toBeVisible(); }); }) @@ -117,43 +117,43 @@ test.describe("User Login", () => { await page.fill('input[name="password"]', 'wrongpassword123'); await page.getByRole('button', { name: 'Login' }).click(); - await expect(page.locator('.alert-danger')).toContainText(/invalid.*credentials|incorrect.*email.*password|login.*failed/i); + await expect(page.locator('.alert-danger')).toBeVisible(); await expect(page).toHaveURL(/login/); }); }) test.describe("Role Based Access Control", () => { - test('admin users can access admin features', async ({ page }) => { - await page.goto('/login.php'); + test.describe("Admin Role", () => { + test.use({ storageState: 'playwright/.auth/admin.json' }); - await page.fill('input[name="email"]', TEST_ADMIN_EMAIL); - await page.fill('input[name="password"]', TEST_ADMIN_PASSWORD); - await page.getByRole('button', { name: 'Login' }).click(); + test('admin users can access admin features', async ({ page }) => { + await page.goto('/login.php'); - await expect(page).toHaveURL(/dashboard/); - await expect(page.locator('span.badge-role')).toHaveText(/Admin/i); + await expect(page).toHaveURL(/dashboard/); + await expect(page.locator('span.badge-role')).toHaveText(/Admin/i); + }); }); - test('lawyers can access lawyer features', async ({ page }) => { - await page.goto('/login.php'); + test.describe("Lawyer Role", () => { + test.use({ storageState: 'playwright/.auth/lawyer.json' }); - await page.fill('input[name="email"]', TEST_LAWYER_EMAIL); - await page.fill('input[name="password"]', TEST_LAWYER_PASSWORD); - await page.getByRole('button', { name: 'Login' }).click(); + test('lawyers can access lawyer features', async ({ page }) => { + await page.goto('/login.php'); - await expect(page).toHaveURL(/dashboard/); - await expect(page.locator('span.badge-role')).toHaveText(/Lawyer/i); + await expect(page).toHaveURL(/dashboard/); + await expect(page.locator('span.badge-role')).toHaveText(/Lawyer/i); + }); }); - test('clients can access client features', async ({ page }) => { - await page.goto('/login.php'); + test.describe("Client Role", () => { + test.use({ storageState: 'playwright/.auth/client.json' }); - await page.fill('input[name="email"]', TEST_CLIENT_EMAIL); - await page.fill('input[name="password"]', TEST_CLIENT_PASSWORD); - await page.getByRole('button', { name: 'Login' }).click(); + test('clients can access client features', async ({ page }) => { + await page.goto('/login.php'); - await expect(page).toHaveURL(/dashboard/); - await expect(page.locator('span.badge-role')).toHaveText(/Client/i); + await expect(page).toHaveURL(/dashboard/); + await expect(page.locator('span.badge-role')).toHaveText(/Client/i); + }); }); });