mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-29 20:19:04 +01:00
135 lines
4.8 KiB
TypeScript
135 lines
4.8 KiB
TypeScript
import test, { expect, type Page } from '@playwright/test';
|
||
import authUtil from 'utils/auth.util';
|
||
import { oidcClients } from '../data';
|
||
import { cleanupBackend } from '../utils/cleanup.util';
|
||
|
||
test.beforeEach(async () => await cleanupBackend());
|
||
|
||
function apps(page: Page) {
|
||
return page.getByRole('list', { name: 'All apps' }).getByRole('listitem');
|
||
}
|
||
|
||
function app(page: Page, name: string) {
|
||
return page.getByRole('listitem').filter({ has: page.getByText(name, { exact: true }) });
|
||
}
|
||
|
||
test('Dashboard shows only clients with launch URLs in the correct order', async ({ page }) => {
|
||
const client1 = oidcClients.nextcloud;
|
||
const client2 = oidcClients.immich;
|
||
|
||
await page.goto('/settings/apps');
|
||
|
||
await expect(apps(page)).toHaveCount(2);
|
||
|
||
// Should be first
|
||
const tile1 = apps(page).first();
|
||
await expect(tile1.getByRole('link')).toHaveText(client1.name);
|
||
await expect(tile1.getByText(new URL(client1.launchURL).hostname)).toBeVisible();
|
||
|
||
const tile2 = app(page, client2.name);
|
||
await expect(tile2.getByRole('link', { name: client2.name })).toBeVisible();
|
||
await expect(tile2.getByText(new URL(client2.launchURL).hostname)).toBeVisible();
|
||
|
||
await expect(app(page, oidcClients.tailscale.name)).toHaveCount(0);
|
||
});
|
||
|
||
test.describe('Dashboard shows only clients where user has access', () => {
|
||
test("User can't see a restricted launchable client", async ({ page }) => {
|
||
await authUtil.changeUser(page, 'craig');
|
||
await page.goto('/settings/apps');
|
||
|
||
await expect(apps(page)).toHaveCount(1);
|
||
await expect(app(page, oidcClients.nextcloud.name)).toBeVisible();
|
||
await expect(app(page, oidcClients.immich.name)).toHaveCount(0);
|
||
});
|
||
|
||
test('User can see every accessible launchable client', async ({ page }) => {
|
||
await page.goto('/settings/apps');
|
||
|
||
await expect(apps(page)).toHaveCount(2);
|
||
await expect(app(page, oidcClients.nextcloud.name)).toBeVisible();
|
||
await expect(app(page, oidcClients.immich.name)).toBeVisible();
|
||
});
|
||
});
|
||
|
||
test('Show and revoke an app without a launch link', async ({ page }) => {
|
||
const client = oidcClients.tailscale;
|
||
|
||
await page.goto('/settings/apps');
|
||
|
||
const clientRow = app(page, client.name);
|
||
await expect(clientRow).toHaveCount(0);
|
||
|
||
await page.getByRole('button', { name: /Apps without a launch link/ }).click();
|
||
|
||
await expect(
|
||
page.getByRole('list', { name: /Apps without a launch link/ }).getByRole('listitem')
|
||
).toHaveCount(2);
|
||
await expect(clientRow).toBeVisible();
|
||
await expect(clientRow.getByRole('link')).toHaveCount(0);
|
||
await clientRow.getByRole('button', { name: `Actions for ${client.name}` }).click();
|
||
await page.getByRole('menuitem', { name: 'Revoke access…' }).click();
|
||
await page.getByRole('alertdialog').getByRole('button', { name: 'Revoke' }).click();
|
||
|
||
await expect(page.getByText(`${client.name}’s access revoked`, { exact: true })).toBeVisible();
|
||
await expect(clientRow).toHaveCount(0);
|
||
});
|
||
|
||
test('Launch authorized client', async ({ page }) => {
|
||
const client = oidcClients.nextcloud;
|
||
|
||
await page.goto('/settings/apps');
|
||
|
||
await expect(app(page, client.name).getByRole('link', { name: client.name })).toHaveAttribute(
|
||
'href',
|
||
client.launchURL
|
||
);
|
||
});
|
||
|
||
test('Sort apps by name and remember the choice', async ({ page }) => {
|
||
await page.goto('/settings/apps');
|
||
|
||
const sortButton = page.getByRole('button', { name: 'Sort by' });
|
||
await expect(apps(page).first().getByRole('link')).toHaveText(oidcClients.nextcloud.name);
|
||
|
||
await sortButton.click();
|
||
await page.getByRole('menuitemradio', { name: 'Name A–Z' }).click();
|
||
await expect(apps(page).first().getByRole('link')).toHaveText(oidcClients.immich.name);
|
||
|
||
await page.reload();
|
||
await expect(apps(page).first().getByRole('link')).toHaveText(oidcClients.immich.name);
|
||
|
||
await sortButton.click();
|
||
await expect(page.getByRole('menuitemradio', { name: 'Name A–Z' })).toHaveAttribute(
|
||
'aria-checked',
|
||
'true'
|
||
);
|
||
await page.getByRole('menuitemradio', { name: 'Name Z–A' }).click();
|
||
await expect(apps(page).first().getByRole('link')).toHaveText(oidcClients.nextcloud.name);
|
||
});
|
||
|
||
test('Search apps by name', async ({ page }) => {
|
||
await page.goto('/settings/apps');
|
||
|
||
const searchInput = page.getByRole('searchbox', { name: 'Search apps' });
|
||
|
||
await searchInput.fill('NEXT');
|
||
await expect(apps(page)).toHaveCount(1);
|
||
await expect(app(page, oidcClients.nextcloud.name)).toBeVisible();
|
||
|
||
await searchInput.fill('does-not-exist');
|
||
await expect(page.getByText('No apps match “does-not-exist”')).toBeVisible();
|
||
await expect(apps(page)).toHaveCount(0);
|
||
|
||
await page.getByRole('button', { name: 'Clear search' }).click();
|
||
await expect(apps(page)).toHaveCount(2);
|
||
});
|
||
|
||
test('Search also finds apps without a launch link', async ({ page }) => {
|
||
await page.goto('/settings/apps');
|
||
|
||
await page.getByRole('searchbox', { name: 'Search apps' }).fill(oidcClients.tailscale.name);
|
||
await expect(apps(page)).toHaveCount(0);
|
||
await expect(app(page, oidcClients.tailscale.name)).toBeVisible();
|
||
});
|