electron-playwright-helpers
Version:
Helper functions for Electron end-to-end testing using Playwright
215 lines • 8.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWindowByUrl = getWindowByUrl;
exports.getWindowByTitle = getWindowByTitle;
exports.getWindowByMatcher = getWindowByMatcher;
exports.waitForWindowByUrl = waitForWindowByUrl;
exports.waitForWindowByTitle = waitForWindowByTitle;
exports.waitForWindowByMatcher = waitForWindowByMatcher;
const utilities_1 = require("./utilities");
/**
* Helper to match a string against a pattern (string or RegExp).
* For strings, performs a substring match (includes).
* For RegExp, tests the pattern against the value.
*/
function matchesPattern(value, pattern) {
if (pattern instanceof RegExp) {
return pattern.test(value);
}
return value.includes(pattern);
}
async function getWindowByUrl(electronApp, pattern, options) {
return getWindowByMatcher(electronApp, async (page) => {
const url = page.url();
if (!url) {
try {
await page.waitForURL((u) => !!u, { timeout: 1000 });
}
catch {
return false;
}
}
return matchesPattern(page.url(), pattern);
}, options);
}
async function getWindowByTitle(electronApp, pattern, options) {
return getWindowByMatcher(electronApp, async (page) => {
const title = await page.title();
return matchesPattern(title, pattern);
}, options);
}
async function getWindowByMatcher(electronApp, matcher, options) {
const { all, ...retryOpts } = options || {};
const findWindows = async () => {
const windows = electronApp.windows();
if (all) {
const results = [];
for (const page of windows) {
if (await matcher(page)) {
results.push(page);
}
}
return results;
}
// Return first match
for (const page of windows) {
if (await matcher(page)) {
return page;
}
}
return undefined;
};
return (0, utilities_1.retry)(findWindows, retryOpts);
}
// ============================================================================
// waitForWindowByUrl
// ============================================================================
/**
* Wait for a window whose URL matches the given pattern.
*
* This function checks existing windows first, then listens for new windows.
* It uses polling to handle windows that may have their URL change after opening.
*
* @category Window Helpers
*
* @param electronApp - The Playwright ElectronApplication
* @param pattern - A string (substring match) or RegExp to match against the URL
* @param options - Optional timeout and interval settings
* @returns The matching Page
* @throws Error if timeout is reached before a matching window is found
*
* @example
* ```ts
* // Click something that opens a new window, then wait for it
* await page.click('#open-settings')
* const settingsWindow = await waitForWindowByUrl(app, '/settings', { timeout: 5000 })
* ```
*/
async function waitForWindowByUrl(electronApp, pattern, options) {
return waitForWindowByMatcher(electronApp, async (page) => {
const url = page.url();
if (!url) {
try {
await page.waitForURL((u) => !!u, { timeout: 1000 });
}
catch {
return false;
}
}
return matchesPattern(page.url(), pattern);
}, options);
}
// ============================================================================
// waitForWindowByTitle
// ============================================================================
/**
* Wait for a window whose title matches the given pattern.
*
* This function checks existing windows first, then listens for new windows.
* It uses polling to handle windows that may have their title change after opening.
*
* @category Window Helpers
*
* @param electronApp - The Playwright ElectronApplication
* @param pattern - A string (substring match) or RegExp to match against the title
* @param options - Optional timeout and interval settings
* @returns The matching Page
* @throws Error if timeout is reached before a matching window is found
*
* @example
* ```ts
* // Wait for a window with a specific title to appear
* const prefsWindow = await waitForWindowByTitle(app, 'Preferences', { timeout: 5000 })
* ```
*/
async function waitForWindowByTitle(electronApp, pattern, options) {
return waitForWindowByMatcher(electronApp, async (page) => {
const title = await page.title();
return matchesPattern(title, pattern);
}, options);
}
// ============================================================================
// waitForWindowByMatcher
// ============================================================================
/**
* Wait for a window that matches the provided matcher function.
*
* This function:
* 1. Checks existing windows first
* 2. Listens for new window events
* 3. Polls existing windows periodically (to catch URL/title changes)
*
* @category Window Helpers
*
* @param electronApp - The Playwright ElectronApplication
* @param matcher - A function that receives a Page and returns true if it matches
* @param options - Optional timeout and interval settings
* @returns The matching Page
* @throws Error if timeout is reached before a matching window is found
*
* @example
* ```ts
* const window = await waitForWindowByMatcher(app, async (page) => {
* const title = await page.title()
* return title.startsWith('Document:')
* }, { timeout: 10000 })
* ```
*/
async function waitForWindowByMatcher(electronApp, matcher, options) {
var _a, _b;
const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : 10000;
const interval = (_b = options === null || options === void 0 ? void 0 : options.interval) !== null && _b !== void 0 ? _b : 200;
// Check existing windows first
const windows = electronApp.windows();
for (const page of windows) {
if (await matcher(page)) {
return page;
}
}
// Track the polling interval so we can clean it up
let pollIntervalId;
// Race between:
// 1. waitForEvent('window') with predicate for new windows
// 2. Polling existing windows for changes (URL/title may change after load)
try {
return await Promise.race([
// Wait for new window that matches
electronApp.waitForEvent('window', {
timeout,
predicate: matcher,
}),
// Poll existing windows
new Promise((resolve, reject) => {
const startTime = Date.now();
pollIntervalId = setInterval(async () => {
try {
if (Date.now() - startTime > timeout) {
clearInterval(pollIntervalId);
reject(new Error(`Timeout waiting for window matching criteria after ${timeout}ms`));
return;
}
const windows = electronApp.windows();
for (const page of windows) {
if (await matcher(page)) {
clearInterval(pollIntervalId);
resolve(page);
return;
}
}
}
catch (error) {
clearInterval(pollIntervalId);
reject(error);
}
}, interval);
}),
]);
}
finally {
// Clean up the polling interval when the race completes
if (pollIntervalId !== undefined) {
clearInterval(pollIntervalId);
}
}
}
//# sourceMappingURL=window_helpers.js.map