diff --git a/tests/specs/account-settings.spec.ts b/tests/specs/account-settings.spec.ts index b5da2213..28ecb071 100644 --- a/tests/specs/account-settings.spec.ts +++ b/tests/specs/account-settings.spec.ts @@ -107,7 +107,7 @@ test('Delete passkey from account', async ({ page }) => { await page.goto('/settings/account'); await page.getByLabel('Delete').first().click(); - await page.getByText('Delete', { exact: true }).click(); + await page.getByLabel('Delete Passkey').getByRole('button', { name: 'Delete' }).click(); await expect(page.locator('[data-type="success"]')).toHaveText('Passkey deleted successfully'); }); diff --git a/tests/specs/api-key.spec.ts b/tests/specs/api-key.spec.ts index 57c70ff4..99711ce8 100644 --- a/tests/specs/api-key.spec.ts +++ b/tests/specs/api-key.spec.ts @@ -1,5 +1,5 @@ // frontend/tests/api-key.spec.ts -import { expect, Page, test } from '@playwright/test'; +import { expect, type Page, test } from '@playwright/test'; import { apiKeys } from '../data'; import { cleanupBackend } from '../utils/cleanup.util'; @@ -17,9 +17,14 @@ test.describe('API Key Management', () => { await page.getByLabel('Name').fill(name); await page.getByLabel('Description').fill('Created by automated test'); - // Choose the date - const currentDate = new Date(); - await selectDate(page, currentDate.getFullYear() + 1, currentDate.getMonth(), 1); + const expectedDate = getDefaultApiKeyExpirationDate(); + await expect(page.getByRole('button', { name: 'Select a date' })).toHaveText( + expectedDate.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }) + ); // Submit the form await page.getByRole('button', { name: 'Save' }).click(); @@ -41,6 +46,9 @@ test.describe('API Key Management', () => { // Verify the key appears in the list await expect(page.getByRole('cell', { name }).first()).toContainText(name); + await expect( + page.getByRole('row', { name }).getByRole('cell', { name: expectedDate.toLocaleString() }) + ).toBeVisible(); }); test('Renew API key', async ({ page }) => { @@ -53,9 +61,15 @@ test.describe('API Key Management', () => { await page.getByRole('menuitem', { name: 'Renew' }).click(); - // Choose the date - const currentDate = new Date(); - await selectDate(page, currentDate.getFullYear() + 1, currentDate.getMonth(), 1); + const expectedDate = getDefaultApiKeyExpirationDate(); + await selectApiKeyExpirationDate(page, expectedDate); + await expect(page.getByRole('button', { name: 'Select a date' })).toHaveText( + expectedDate.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }) + ); await page.getByRole('button', { name: 'Renew' }).click(); @@ -63,8 +77,9 @@ test.describe('API Key Management', () => { // Verify the new expiration date is shown const row = page.getByRole('row', { name: apiKey.name }); - const expectedDate = new Date(currentDate.getFullYear() + 1, currentDate.getMonth(), 1); - await expect(row.getByRole('cell', { name: expectedDate.toLocaleString() })).toBeVisible(); + await expect( + row.getByRole('cell', { name: new RegExp(escapeRegExp(expectedDate.toLocaleDateString())) }) + ).toBeVisible(); }); test('Revoke API key', async ({ page }) => { @@ -87,32 +102,28 @@ test.describe('API Key Management', () => { }); }); -async function selectDate(page: Page, year: number, month: number, day: number) { - // Open the date picker - await page.getByRole('button', { name: 'Select a date' }).click(); - // Select the year - await page.getByLabel('Select year').click(); - await page.getByRole('option', { name: year.toString() }).click(); - // Select the month and day - const monthNames = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December' - ]; - const monthName = monthNames[month]; - await page.getByRole('button', { name: 'Select month' }).click(); - await page.getByRole('option', { name: monthName }).click(); - - await page - .getByRole('button', { name: new RegExp(`([A-Z][a-z]+), ([A-Z][a-z]+) ${day}, (\\d{4})`) }).first() - .click(); +function getDefaultApiKeyExpirationDate() { + const date = new Date(); + date.setDate(date.getDate() + 30); + date.setHours(0, 0, 0, 0); + return date; +} + +async function selectApiKeyExpirationDate(page: Page, date: Date) { + await page.getByRole('button', { name: 'Select a date' }).click(); + await page.getByRole('button', { name: 'Next', exact: true }).click(); + await page.getByRole('button', { name: getCalendarDayName(date) }).click(); +} + +function getCalendarDayName(date: Date) { + return new Intl.DateTimeFormat('en-US', { + weekday: 'long', + month: 'long', + day: 'numeric', + year: 'numeric' + }).format(date); +} + +function escapeRegExp(value: string) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } diff --git a/tests/specs/oidc.spec.ts b/tests/specs/oidc.spec.ts index 447bdd5c..4c1aa30a 100644 --- a/tests/specs/oidc.spec.ts +++ b/tests/specs/oidc.spec.ts @@ -33,8 +33,7 @@ test('Authorize new client', async ({ page }) => { const urlParams = createUrlParams(oidcClient); await page.goto(`/authorize?${urlParams.toString()}`); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Profile' })).toBeVisible(); + await expectScopes(page, ['Email', 'Profile']); await expectCallbackRedirect(page, oidcClient.callbackUrl, () => page.getByRole('button', { name: 'Sign in' }).click() @@ -50,8 +49,7 @@ test('Authorize new client while not signed in', async ({ page }) => { await (await passkeyUtil.init(page)).addPasskey(); await page.getByRole('button', { name: 'Sign in' }).click(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Profile' })).toBeVisible(); + await expectScopes(page, ['Email', 'Profile']); await expectCallbackRedirect(page, oidcClient.callbackUrl, () => page.getByRole('button', { name: 'Sign in' }).click() @@ -67,8 +65,7 @@ test('Authorize new client fails with user group not allowed', async ({ page }) await (await passkeyUtil.init(page)).addPasskey('craig'); await page.getByRole('button', { name: 'Sign in' }).click(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Profile' })).toBeVisible(); + await expectScopes(page, ['Email', 'Profile']); await page.getByRole('button', { name: 'Sign in' }).click(); @@ -88,6 +85,15 @@ function createUrlParams(oidcClient: { id: string; callbackUrl: string }) { }); } +async function expectScopes(page: Page, scopes: string[]) { + const scopeList = page.getByTestId('scopes').filter({ hasText: scopes[0] }).last(); + await expect(scopeList).toBeVisible(); + + for (const scope of scopes) { + await expect(scopeList.getByText(scope, { exact: true })).toBeVisible(); + } +} + test('End session without id token hint shows confirmation page', async ({ page }) => { await page.goto('/api/oidc/end-session'); @@ -451,8 +457,7 @@ test('Authorize new client with device authorization flow', async ({ page }) => await page.goto(`/device?code=${userCode}`); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Profile' })).toBeVisible(); + await expectScopes(page, ['Email', 'Profile']); await page.getByRole('button', { name: 'Authorize' }).click(); @@ -473,8 +478,7 @@ test('Authorize new client with device authorization flow while not signed in', await (await passkeyUtil.init(page)).addPasskey(); await page.getByRole('button', { name: 'Authorize' }).click(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Profile' })).toBeVisible(); + await expectScopes(page, ['Email', 'Profile']); await page.getByRole('button', { name: 'Authorize' }).click(); @@ -531,8 +535,7 @@ test('Authorize new client with device authorization with user group not allowed await (await passkeyUtil.init(page)).addPasskey('craig'); await page.getByRole('button', { name: 'Authorize' }).click(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Profile' })).toBeVisible(); + await expectScopes(page, ['Email', 'Profile']); await page.getByRole('button', { name: 'Authorize' }).click(); @@ -765,10 +768,7 @@ test.describe('OIDC prompt parameter', () => { await page.goto(`/authorize?${urlParams.toString()}`); // Should show consent UI even though client was already authorized - await expect( - page.getByTestId('scopes').getByRole('heading', { name: 'Profile' }) - ).toBeVisible(); - await expect(page.getByTestId('scopes').getByRole('heading', { name: 'Email' })).toBeVisible(); + await expectScopes(page, ['Profile', 'Email']); await expectCallbackRedirect(page, oidcClient.callbackUrl, () => page.getByRole('button', { name: 'Sign in' }).click() @@ -1049,9 +1049,7 @@ test.describe('Pushed Authorization Requests (PAR)', () => { await page.goto(`/authorize?${urlParams.toString()}`); // Consent screen with the requested scope (resolved from the PAR) must be shown - await expect( - page.getByTestId('scopes').getByRole('heading', { name: 'Profile' }) - ).toBeVisible(); + await expectScopes(page, ['Profile']); // Confirming proceeds with the authorization await expectCallbackRedirect(page, client.callbackUrl, () => diff --git a/tests/specs/user-signup.spec.ts b/tests/specs/user-signup.spec.ts index e178f502..1ad2ae16 100644 --- a/tests/specs/user-signup.spec.ts +++ b/tests/specs/user-signup.spec.ts @@ -34,7 +34,7 @@ test.describe('Signup Token Creation', () => { test('Create signup token', async ({ page }) => { await page.goto('/settings/admin/users'); - await page.getByLabel('Create options').getByRole('button').click(); + await page.getByRole('button', { name: 'Create options' }).click(); await page.getByRole('menuitem', { name: 'Create Signup Token' }).click(); await page.getByLabel('Expiration').click(); await page.getByRole('option', { name: 'week' }).click(); @@ -49,7 +49,7 @@ test.describe('Signup Token Creation', () => { await page.getByRole('button', { name: 'Create', exact: true }).click(); await page.getByRole('button', { name: 'Close' }).click(); - await page.getByLabel('Create options').getByRole('button').click(); + await page.getByRole('button', { name: 'Create options' }).click(); await page.getByRole('menuitem', { name: 'View Active Signup Tokens' }).click(); await page.getByLabel('Manage Signup Tokens').getByRole('button', { name: 'View' }).click();