mirror of
https://github.com/nextcloud/server.git
synced 2026-10-21 09:15:45 +02:00
The dialog only appears once a session's confirmation window has expired, so the old helper probed for it for 500 ms and silently skipped it on a slow shard, leaving the guarded request unsent; its wait for the dialog to close was unbounded. Install a locator handler per logged-in page instead, and use awaitPasswordGuardedRequest() where a response promise is awaited, since handlers never run during a bare waitForResponse. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
/*
|
|
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
import type { Locator, Page } from '@playwright/test'
|
|
|
|
import { expect } from '@playwright/test'
|
|
|
|
const GUARDED_REQUEST_TIMEOUT = 30_000
|
|
|
|
/**
|
|
* The password confirmation dialog.
|
|
*
|
|
* @param page - The Playwright page object
|
|
*/
|
|
export function passwordConfirmationDialog(page: Page): Locator {
|
|
return page.getByRole('dialog', { name: 'Authentication required' })
|
|
}
|
|
|
|
/**
|
|
* Answer the password confirmation dialog whenever it blocks this page.
|
|
*
|
|
* The server only asks again once the session's last confirmation has expired,
|
|
* so a test cannot know upfront whether the dialog will show up. A locator
|
|
* handler covers both outcomes without probing for it.
|
|
*
|
|
* @param page - The Playwright page object
|
|
* @param password - The password of the account the page is logged in as
|
|
*/
|
|
export async function installPasswordConfirmationHandler(page: Page, password: string): Promise<void> {
|
|
const dialog = passwordConfirmationDialog(page)
|
|
|
|
await page.addLocatorHandler(dialog, async (confirmation) => {
|
|
// password inputs have no accessible role
|
|
await confirmation.locator('input[type="password"]').fill(password)
|
|
await confirmation.getByRole('button', { name: 'Confirm' }).click()
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Await a request that a password confirmation may gate.
|
|
*
|
|
* Locator handlers only run while Playwright performs an action or an
|
|
* auto-waiting assertion, never while a response promise is awaited on its own,
|
|
* so the dialog would stay unanswered until the test times out.
|
|
*
|
|
* @param page - The Playwright page object
|
|
* @param pending - Response promise, registered before the request was triggered
|
|
*/
|
|
export async function awaitPasswordGuardedRequest<T>(page: Page, pending: Promise<T>): Promise<T> {
|
|
let settled = false
|
|
const tracked = pending.finally(() => {
|
|
settled = true
|
|
})
|
|
// the poll below can give up before `pending` settles
|
|
tracked.catch(() => {})
|
|
|
|
const dialog = passwordConfirmationDialog(page)
|
|
await expect(async () => {
|
|
await expect(dialog).toBeHidden({ timeout: 1_000 })
|
|
expect(settled, 'the guarded request did not complete').toBe(true)
|
|
}).toPass({ timeout: GUARDED_REQUEST_TIMEOUT })
|
|
|
|
return tracked
|
|
}
|