Files
bruno/tests/utils/page/runner.ts

192 lines
7.9 KiB
TypeScript

import { Page, expect } from '../../../playwright';
/**
* Reads test result counts from the filter buttons in the runner results view
* @param page - The Playwright page object
* @returns An object with totalRequests, passed, failed, and skipped counts
*/
export const getRunnerResultCounts = async (page: Page) => {
const allButton = page.locator('button').filter({ hasText: /^All/ });
const passedButton = page.locator('button').filter({ hasText: /^Passed/ });
const failedButton = page.locator('button').filter({ hasText: /^Failed/ });
const skippedButton = page.locator('button').filter({ hasText: /^Skipped/ });
const totalRequests = parseInt(await allButton.locator('span').innerText());
const passed = parseInt(await passedButton.locator('span').innerText());
const failed = parseInt(await failedButton.locator('span').innerText());
const skipped = parseInt(await skippedButton.locator('span').innerText());
return { totalRequests, passed, failed, skipped };
};
/**
* Runs a collection by clicking the Run menu item and handling the runner tab
* Includes logic to reset existing results if present
* @param page - The Playwright page object
* @param collectionName - The name of the collection to run
* @returns void
*/
export const runCollection = async (page: Page, collectionName: string) => {
// Ensure collection is visible and loaded
const collectionContainer = page.locator('.collection-name').filter({ hasText: collectionName });
await collectionContainer.waitFor({ state: 'visible' });
// Wait a bit for the UI to stabilize
await page.waitForTimeout(300);
// Open collection actions menu
await collectionContainer.locator('.collection-actions').hover();
const icon = collectionContainer.locator('.collection-actions .icon');
await icon.waitFor({ state: 'visible', timeout: 5000 });
await page.waitForTimeout(200); // Small delay to ensure hover state is stable
await icon.click();
// Click Run menu item
await page.getByText('Run', { exact: true }).click();
// Handle runner tab - reset if needed, then run
const resetButton = page.getByRole('button', { name: 'Reset' });
const runCollectionButton = page.getByRole('button', { name: 'Run Collection' });
// Check if Reset button is visible (means there are existing results)
const resetVisible = await resetButton.isVisible().catch(() => false);
if (resetVisible) {
await resetButton.click();
// Wait a bit for the reset to complete
await page.waitForTimeout(500);
}
// Now wait for and click Run Collection button
await runCollectionButton.waitFor({ state: 'visible', timeout: 10000 });
await runCollectionButton.click();
// Wait for the run to complete
await page.getByRole('button', { name: 'Run Again' }).waitFor({ timeout: 2 * 60 * 1000 });
};
/**
* Sets up the JavaScript sandbox mode for a collection
* @param page - The Playwright page object
* @param collectionName - The name of the collection (can be title or text)
* @param mode - 'developer' or 'safe' mode
* @returns void
*/
export const setSandboxMode = async (page: Page, collectionName: string, mode: 'developer' | 'safe') => {
// Click on the collection name - try sidebar first, then fall back to collection tab/name
// First try sidebar collection name (more reliable)
const sidebarCollection = page.locator('#sidebar-collection-name').filter({ hasText: collectionName });
const sidebarExists = await sidebarCollection.count().then((count) => count > 0).catch(() => false);
if (sidebarExists) {
await sidebarCollection.click();
} else {
// Fall back to collection by title or text
const collectionByTitle = page.getByTitle(collectionName);
const collectionByText = page.getByText(collectionName);
const titleExists = await collectionByTitle.count().then((count) => count > 0).catch(() => false);
if (titleExists) {
await collectionByTitle.click();
} else {
await collectionByText.click();
}
}
// Wait a moment for the UI to load
await page.waitForTimeout(300);
// Check if there's already a mode selected - if so, we need to click the badge to open settings tab
// Look for the Developer Mode or Safe Mode badge/button
const developerModeBadge = page.locator('.developer-mode').filter({ hasText: 'Developer Mode' });
const safeModeBadge = page.locator('.safe-mode').filter({ hasText: 'Safe Mode' });
const developerBadgeExists = await developerModeBadge.count().then((count) => count > 0).catch(() => false);
const safeBadgeExists = await safeModeBadge.count().then((count) => count > 0).catch(() => false);
// If a badge exists, click it to open the security settings tab
if (developerBadgeExists || safeBadgeExists) {
// Click the appropriate badge to open the security settings tab
if (developerBadgeExists) {
await developerModeBadge.click();
} else {
await safeModeBadge.click();
}
// Wait for the security settings tab to be active and form to be visible
// Look for the security settings content - it should have "JavaScript Sandbox" heading
await page.getByText('JavaScript Sandbox').waitFor({ state: 'visible', timeout: 10000 });
await page.waitForTimeout(300);
}
// If no badge exists, the modal should have appeared automatically (first time selection)
// Wait for security settings form to be visible - wait for either radio button
// These should be in the active tab (either modal or tab)
const safeModeRadio = page.getByLabel('Safe Mode');
const developerRadio = page.getByLabel('Developer Mode(use only if');
// Wait for at least one of them to be visible
await Promise.race([
safeModeRadio.waitFor({ state: 'visible', timeout: 10000 }).catch(() => {}),
developerRadio.waitFor({ state: 'visible', timeout: 10000 }).catch(() => {})
]);
// Additional wait to ensure UI is stable
await page.waitForTimeout(300);
if (mode === 'developer') {
await developerRadio.waitFor({ state: 'visible', timeout: 5000 });
await developerRadio.check();
} else {
// For safe mode, check if developer mode is currently selected
const developerModeChecked = await developerRadio.isChecked().catch(() => false);
if (developerModeChecked) {
// Click the Developer Mode label text inside the security settings form
// Scope to the form container to avoid clicking the badge
// The form should have the "JavaScript Sandbox" heading, so scope to that container
const securityForm = page.locator('div').filter({ hasText: 'JavaScript Sandbox' }).locator('..').first();
const developerLabel = securityForm.locator('label').filter({ hasText: /^Developer Mode/ }).first();
await developerLabel.waitFor({ state: 'visible', timeout: 5000 });
await developerLabel.click();
// Wait for UI to update
await page.waitForTimeout(300);
}
// Ensure Safe Mode radio is visible and check it
await safeModeRadio.waitFor({ state: 'visible', timeout: 5000 });
await safeModeRadio.check();
}
await page.getByRole('button', { name: 'Save' }).click();
};
/**
* Validates runner results against expected counts
* @param page - The Playwright page object
* @param expected - Expected counts
* @returns void
*/
export const validateRunnerResults = async (page: Page,
expected: {
totalRequests?: number;
passed?: number;
failed?: number;
skipped?: number;
}) => {
const { totalRequests, passed, failed, skipped } = await getRunnerResultCounts(page);
if (expected.totalRequests !== undefined) {
await expect(totalRequests).toBe(expected.totalRequests);
}
if (expected.passed !== undefined) {
await expect(passed).toBe(expected.passed);
}
if (expected.failed !== undefined) {
await expect(failed).toBe(expected.failed);
}
if (expected.skipped !== undefined) {
await expect(skipped).toBe(expected.skipped);
}
// Validate that passed + failed + skipped = totalRequests
await expect(passed).toBe(totalRequests - skipped - failed);
};