tests(e2e): fix locators after shadcn upgrade

This commit is contained in:
Elias Schneider
2026-06-21 20:52:42 +02:00
parent 80509c83ee
commit dbbe2a403a
4 changed files with 68 additions and 59 deletions

View File

@@ -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');
});

View File

@@ -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, '\\$&');
}

View File

@@ -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, () =>

View File

@@ -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();