chore: test fixes

This commit is contained in:
Bijin A B
2026-03-21 20:25:48 +05:30
parent dded9278e0
commit 45a0af62fd
11 changed files with 81 additions and 103 deletions

View File

@@ -1,13 +1,14 @@
import { test, expect, closeElectronApp } from '../../playwright';
import * as path from 'path';
import * as fs from 'fs/promises';
import { waitForReadyPage } from '../utils/page';
test('should handle corrupted passkey and still display saved cookie list', async ({ createTmpDir, launchElectronApp }) => {
const userDataPath = await createTmpDir('corrupted-passkey');
const app1 = await launchElectronApp({ userDataPath });
// 1. First run add a cookie via the UI so `cookies.json` is created.
const page1 = await app1.firstWindow();
const page1 = await waitForReadyPage(app1);
await page1.waitForSelector('[data-trigger="cookies"]');
await page1.click('[data-trigger="cookies"]');
@@ -35,7 +36,7 @@ test('should handle corrupted passkey and still display saved cookie list', asyn
// 3. Second run Bruno should recover and still list the cookie domain
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
const page2 = await waitForReadyPage(app2);
await page2.waitForSelector('[data-trigger="cookies"]');
await page2.click('[data-trigger="cookies"]');

View File

@@ -1,5 +1,5 @@
import { test, expect, closeElectronApp } from '../../../playwright';
import { sendRequest } from '../../utils/page';
import { sendRequest, waitForReadyPage } from '../../utils/page';
test.describe.serial('bru.setEnvVar(name, value, { persist: true })', () => {
test('set env var with persist using script', async ({ pageWithUserData: page, restartApp }) => {
@@ -23,8 +23,8 @@ test.describe.serial('bru.setEnvVar(name, value, { persist: true })', () => {
await page.getByTestId('environment-selector-trigger').click();
// open environment configuration
await page.locator('#configure-env').hover();
await page.locator('#configure-env').click();
await page.locator('#configure-env').waitFor({ state: 'visible' });
await page.locator('#configure-env').dispatchEvent('click');
const envTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'Environments' }) });
await expect(envTab).toBeVisible();
@@ -36,7 +36,7 @@ test.describe.serial('bru.setEnvVar(name, value, { persist: true })', () => {
// we restart the app to confirm that the environment variable is persisted
const newApp = await restartApp();
const newPage = await newApp.firstWindow();
const newPage = await waitForReadyPage(newApp);
// select the collection and request
await newPage.locator('#sidebar-collection-name').click();
@@ -44,7 +44,8 @@ test.describe.serial('bru.setEnvVar(name, value, { persist: true })', () => {
// open environment dropdown
await newPage.getByTestId('environment-selector-trigger').click();
await newPage.locator('#configure-env').click();
await newPage.locator('#configure-env').waitFor({ state: 'visible' });
await newPage.locator('#configure-env').dispatchEvent('click');
const newEnvTab = newPage.locator('.request-tab').filter({ hasText: 'Environments' });
await expect(newEnvTab).toBeVisible();

View File

@@ -1,5 +1,5 @@
import { test, expect, closeElectronApp } from '../../../playwright';
import { sendRequest } from '../../utils/page';
import { sendRequest, waitForReadyPage } from '../../utils/page';
test.describe.serial('bru.setEnvVar(name, value)', () => {
test('set env var using script', async ({ pageWithUserData: page, restartApp }) => {
@@ -20,7 +20,8 @@ test.describe.serial('bru.setEnvVar(name, value)', () => {
// confirm that the environment variable is set
await page.getByTestId('environment-selector-trigger').click();
await page.locator('#configure-env').click();
await page.locator('#configure-env').waitFor({ state: 'visible' });
await page.locator('#configure-env').dispatchEvent('click');
const envTab = page.locator('.request-tab').filter({ hasText: 'Environments' });
await expect(envTab).toBeVisible();
@@ -32,7 +33,7 @@ test.describe.serial('bru.setEnvVar(name, value)', () => {
// we restart the app to confirm that the environment variable is not persisted
const newApp = await restartApp();
const newPage = await newApp.firstWindow();
const newPage = await waitForReadyPage(newApp);
// select the collection and request
await newPage.locator('#sidebar-collection-name').click();
@@ -40,7 +41,8 @@ test.describe.serial('bru.setEnvVar(name, value)', () => {
// open environment dropdown
await newPage.getByTestId('environment-selector-trigger').click();
await newPage.locator('#configure-env').click();
await newPage.locator('#configure-env').waitFor({ state: 'visible' });
await newPage.locator('#configure-env').dispatchEvent('click');
const newEnvTab = newPage.locator('.request-tab').filter({ hasText: 'Environments' });
await expect(newEnvTab).toBeVisible();

View File

@@ -54,15 +54,20 @@ test.describe('Collection Environment Import Tests', () => {
const envTab = page.locator('.request-tab').filter({ hasText: 'Environments' });
await expect(envTab).toBeVisible();
// Environment variables table uses react-virtuoso (virtual scroll),
// so only visible rows are in the DOM. Verify first visible batch,
// then scroll to reveal the rest.
const envNameInputs = page.locator('input[name$=".name"]');
await expect.poll(async () => envNameInputs.count()).toBeGreaterThanOrEqual(6);
await expect(envNameInputs.nth(0)).toHaveValue('host');
await expect(envNameInputs.nth(1)).toHaveValue('userId');
await expect(envNameInputs.nth(2)).toHaveValue('apiKey');
await expect(envNameInputs.nth(3)).toHaveValue('postTitle');
await expect(envNameInputs.nth(4)).toHaveValue('postBody');
await expect(envNameInputs.nth(5)).toHaveValue('secretApiToken');
// Scroll the virtualized table to reveal remaining rows
await page.locator('.table-container').evaluate((el) => el.scrollTop = el.scrollHeight);
await expect(page.locator('input[name$=".name"][value="postTitle"]')).toBeVisible();
await expect(page.locator('input[name$=".name"][value="postBody"]')).toBeVisible();
await expect(page.locator('input[name$=".name"][value="secretApiToken"]')).toBeVisible();
await expect(page.locator('input[name="5.secret"]')).toBeChecked();
await envTab.hover();
await envTab.getByTestId('request-tab-close-icon').click({ force: true });

View File

@@ -48,10 +48,17 @@ test.describe('Global Environment Import Tests', () => {
const envTab = page.locator('.request-tab').filter({ hasText: 'Global Environments' });
await expect(envTab).toBeVisible();
// Environment variables table uses react-virtuoso (virtual scroll),
// so only visible rows are in the DOM. Verify first visible batch,
// then scroll to reveal the rest.
const variablesTable = page.locator('.table-container');
await expect(variablesTable.locator('input[name="0.name"]')).toHaveValue('host');
await expect(variablesTable.locator('input[name="1.name"]')).toHaveValue('userId');
await expect(variablesTable.locator('input[name="2.name"]')).toHaveValue('apiKey');
// Scroll the virtualized table to reveal remaining rows
await variablesTable.evaluate((el) => el.scrollTop = el.scrollHeight);
await expect(variablesTable.locator('input[name="3.name"]')).toHaveValue('postTitle');
await expect(variablesTable.locator('input[name="4.name"]')).toHaveValue('postBody');
await expect(variablesTable.locator('input[name="5.name"]')).toHaveValue('secretApiToken');

View File

@@ -1,5 +1,6 @@
import path from 'path';
import { test, expect, errors, closeElectronApp } from '../../playwright';
import { waitForReadyPage } from '../utils/page';
const initUserDataPath = path.join(__dirname, 'init-user-data-fresh');
@@ -20,10 +21,7 @@ async function dismissWelcomeModalIfVisible(page: any) {
test.describe('Onboarding', () => {
test('should create sample collection on first launch', async ({ launchElectronApp }) => {
const app = await launchElectronApp({ initUserDataPath, dotEnv: env });
const page = await app.firstWindow();
// Wait for app to load and dismiss welcome modal
await page.locator('[data-app-state="loaded"]').waitFor();
const page = await waitForReadyPage(app);
await dismissWelcomeModalIfVisible(page);
// Verify sample collection appears in sidebar
@@ -49,10 +47,7 @@ test.describe('Onboarding', () => {
// Use a fresh app instance to avoid contamination from previous tests
const userDataPath = await createTmpDir('duplicate-collections');
const app = await launchElectronApp({ userDataPath, initUserDataPath, dotEnv: env });
const page = await app.firstWindow();
// Wait for app to load and dismiss welcome modal
await page.locator('[data-app-state="loaded"]').waitFor();
const page = await waitForReadyPage(app);
await dismissWelcomeModalIfVisible(page);
// First launch - verify sample collection is created
@@ -73,7 +68,7 @@ test.describe('Onboarding', () => {
// Restart app - should not create sample collection again
const newApp = await launchElectronApp({ userDataPath, dotEnv: env });
const newPage = await newApp.firstWindow();
const newPage = await waitForReadyPage(newApp);
// Verify only one sample collection exists
const sampleCollections = newPage.locator('#sidebar-collection-name').getByText('Sample API Collection');
@@ -95,10 +90,7 @@ test.describe('Onboarding', () => {
test('should not recreate sample collection after user deletes it', async ({ launchElectronApp, reuseOrLaunchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('first-launch');
const app = await launchElectronApp({ userDataPath, initUserDataPath, dotEnv: env });
const page = await app.firstWindow();
// Wait for app to load and dismiss welcome modal
await page.locator('[data-app-state="loaded"]').waitFor();
const page = await waitForReadyPage(app);
await dismissWelcomeModalIfVisible(page);
// First launch - sample collection should be created
@@ -134,10 +126,7 @@ test.describe('Onboarding', () => {
// Restart app - sample collection should NOT be recreated
const newApp = await reuseOrLaunchElectronApp({ userDataPath, dotEnv: env });
const newPage = await newApp.firstWindow();
// Wait for the app to be loaded / onboarding to be completed
await newPage.locator('[data-app-state="loaded"]').waitFor();
const newPage = await waitForReadyPage(newApp);
// Sample collection should not appear since it's no longer first launch
const sampleCollections = newPage.locator('#sidebar-collection-name').getByText('Sample API Collection');

View File

@@ -1,6 +1,7 @@
import path from 'path';
import { ElectronApplication } from '@playwright/test';
import { test, expect, closeElectronApp } from '../../playwright';
import { waitForReadyPage } from '../utils/page';
const initUserDataPath = path.join(__dirname, 'init-user-data-fresh');
@@ -10,10 +11,7 @@ test.describe('Welcome Modal', () => {
try {
app = await launchElectronApp({ initUserDataPath });
const page = await app.firstWindow();
// Wait for the app to fully initialize before interacting
await page.locator('[data-app-state="loaded"]').waitFor();
const page = await waitForReadyPage(app);
// Welcome modal should be visible for new users
const welcomeModal = page.getByTestId('welcome-modal');
@@ -43,8 +41,7 @@ test.describe('Welcome Modal', () => {
try {
// Launch app for a new user - welcome modal should appear
app = await launchElectronApp({ userDataPath, initUserDataPath });
let page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor();
let page = await waitForReadyPage(app);
// Welcome modal should be visible for new users
const welcomeModal = page.getByTestId('welcome-modal');
@@ -60,8 +57,7 @@ test.describe('Welcome Modal', () => {
// Restart the app with the same userDataPath
app = await launchElectronApp({ userDataPath });
page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor();
page = await waitForReadyPage(app);
// Welcome modal should NOT appear after restart (hasSeenWelcomeModal persisted)
await expect(page.getByTestId('welcome-modal')).not.toBeVisible();
@@ -77,10 +73,7 @@ test.describe('Welcome Modal', () => {
try {
app = await launchElectronApp({ initUserDataPath });
const page = await app.firstWindow();
// Wait for the app to fully initialize before interacting
await page.locator('[data-app-state="loaded"]').waitFor();
const page = await waitForReadyPage(app);
const welcomeModal = page.getByTestId('welcome-modal');
@@ -110,10 +103,7 @@ test.describe('Welcome Modal', () => {
try {
app = await launchElectronApp({ initUserDataPath });
const page = await app.firstWindow();
// Wait for the app to fully initialize before interacting
await page.locator('[data-app-state="loaded"]').waitFor();
const page = await waitForReadyPage(app);
const welcomeModal = page.getByTestId('welcome-modal');

View File

@@ -18,6 +18,7 @@ test.describe.serial('Response pane updates when focused and request is re-sent'
const requestName = 'Echo Request';
test.beforeAll(async ({ page, createTmpDir }) => {
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 20000 });
const collectionPath = await createTmpDir('response-pane-collection');
await createCollection(page, collectionName, collectionPath);
await createRequest(page, requestName, collectionName, { url: echoUrl, method: 'POST' });

View File

@@ -12,7 +12,7 @@ type WaitForAppReadyOptions = {
* Wait for the Electron app to have a ready, loaded window.
* Handles cases where the first window is slow to appear.
*/
const waitForAppReady = async (
const waitForReadyPage = async (
app: ElectronApplication,
options: WaitForAppReadyOptions = {}
) => {
@@ -59,8 +59,8 @@ const closeAllCollections = async (page) => {
const hasDiscardButton = await page.getByRole('button', { name: 'Discard All and Remove' }).isVisible().catch(() => false);
if (hasDiscardButton) {
// Drafts modal - click "Discard All and Remove"
await page.getByRole('button', { name: 'Discard All and Remove' }).click();
// Drafts modal - click "Discard All and Remove" (force to avoid element stability issues)
await page.getByRole('button', { name: 'Discard All and Remove' }).click({ force: true });
} else {
// Regular modal - click the submit button
await page.locator('.bruno-modal-footer .submit').click();
@@ -1313,7 +1313,7 @@ const openExampleFromSidebar = async (page: Page, requestName: string, exampleNa
};
export {
waitForAppReady,
waitForReadyPage,
closeAllCollections,
openCollection,
createCollection,

View File

@@ -2,7 +2,7 @@ import path from 'path';
import fs from 'fs';
import yaml from 'js-yaml';
import { test, expect } from '../../playwright';
import { createCollection, waitForAppReady } from '../utils/page';
import { createCollection, waitForReadyPage } from '../utils/page';
type WorkspaceConfig = { collections?: { name: string }[] };
@@ -13,7 +13,7 @@ test.describe('Collection reorder persistence', () => {
const colBPath = await createTmpDir('col-b');
const app = await launchElectronApp({ userDataPath });
const page = await waitForAppReady(app);
const page = await waitForReadyPage(app);
await test.step('Create two collections', async () => {
await createCollection(page, 'ColA', colAPath);
@@ -44,7 +44,7 @@ test.describe('Collection reorder persistence', () => {
await test.step('Restart app and verify order persisted', async () => {
const app2 = await launchElectronApp({ userDataPath });
const page2 = await waitForAppReady(app2);
const page2 = await waitForReadyPage(app2);
const rows2 = page2.getByTestId('sidebar-collection-row');
await expect(rows2.nth(0)).toContainText('ColB');
@@ -61,7 +61,7 @@ test.describe('Collection reorder persistence', () => {
const colBPath = await createTmpDir('col-b');
const app = await launchElectronApp({ userDataPath });
const page = await waitForAppReady(app);
const page = await waitForReadyPage(app);
await test.step('Create two collections', async () => {
await createCollection(page, 'ColA', colAPath);

View File

@@ -1,6 +1,7 @@
import path from 'path';
import fs from 'fs';
import { test, expect, closeElectronApp } from '../../../playwright';
import { waitForReadyPage } from '../../utils/page';
test.describe('Default Workspace Recovery and Backup', () => {
test.describe('Global Environments Backup', () => {
@@ -46,8 +47,7 @@ test.describe('Default Workspace Recovery and Backup', () => {
// Launch app - should trigger migration and create backup
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// Verify backup file was created
const backupPath = path.join(userDataPath, 'global-environments-backup.json');
@@ -93,8 +93,8 @@ test.describe('Default Workspace Recovery and Backup', () => {
// First launch
const app1 = await launchElectronApp({ userDataPath });
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app1);
await closeElectronApp(app1);
// Verify backup exists
@@ -104,8 +104,7 @@ test.describe('Default Workspace Recovery and Backup', () => {
// Second launch - backup should still exist
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app2);
// Backup should not be modified on second launch
expect(fs.existsSync(backupPath)).toBe(true);
@@ -136,8 +135,8 @@ test.describe('Default Workspace Recovery and Backup', () => {
// Launch app - triggers migration
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
await closeElectronApp(app);
// Verify lastOpenedCollections is still in preferences
@@ -177,8 +176,7 @@ docs: ''
// Launch app - should discover and use existing workspace
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
const page = await waitForReadyPage(app);
// UI always shows "My Workspace"
await expect(page.getByTestId('workspace-name')).toHaveText('My Workspace');
@@ -225,8 +223,7 @@ docs: ''
// Launch app - should use workspace-2 (latest/highest number)
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
const page = await waitForReadyPage(app);
await expect(page.getByTestId('workspace-name')).toHaveText('My Workspace');
@@ -288,8 +285,7 @@ docs: ''
// Launch app - should skip workspace-2, use workspace-1
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
const page = await waitForReadyPage(app);
await expect(page.getByTestId('workspace-name')).toHaveText('My Workspace');
@@ -345,8 +341,7 @@ docs: ''
// Launch app - should recover collections and create new workspace
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// New workspace should be created
const newWorkspace = path.join(userDataPath, 'default-workspace-1');
@@ -416,8 +411,7 @@ docs: ''
// Launch app
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// New workspace should have recovered environments
const newWorkspace = path.join(userDataPath, 'default-workspace-1');
@@ -456,8 +450,7 @@ docs: ''
// Launch app
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// New workspace should have the collection from lastOpenedCollections
const newWorkspace = path.join(userDataPath, 'default-workspace-1');
@@ -510,8 +503,7 @@ docs: ''
// Launch app - should find and use the existing valid workspace
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
const page = await waitForReadyPage(app);
await expect(page.getByTestId('workspace-name')).toHaveText('My Workspace');
@@ -591,8 +583,7 @@ docs: ''
// Launch app - should use workspace-1 (latest valid)
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
const page = await waitForReadyPage(app);
await expect(page.getByTestId('workspace-name')).toHaveText('My Workspace');
@@ -620,8 +611,7 @@ docs: ''
// First launch - creates workspace
const app1 = await launchElectronApp({ userDataPath });
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app1);
// Verify workspace was created
const workspacePath = path.join(userDataPath, 'default-workspace');
@@ -666,8 +656,7 @@ variables:
// Second launch - should recover
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app2);
// New workspace should exist
const newWorkspace = path.join(userDataPath, 'default-workspace-1');
@@ -684,8 +673,7 @@ variables:
// First launch - creates workspace
const app1 = await launchElectronApp({ userDataPath });
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app1);
const workspacePath = path.join(userDataPath, 'default-workspace');
expect(fs.existsSync(workspacePath)).toBe(true);
@@ -698,8 +686,7 @@ variables:
// Second launch - should create new workspace
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app2);
// New workspace should be created at default-workspace (since it was deleted)
expect(fs.existsSync(workspacePath)).toBe(true);
@@ -727,8 +714,8 @@ variables:
// First launch
const app1 = await launchElectronApp({ userDataPath });
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app1);
await closeElectronApp(app1);
// Verify workspace-0 created
@@ -750,8 +737,8 @@ variables: []
// Second launch - recovery to workspace-1
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app2);
await closeElectronApp(app2);
// Verify workspace-1 created with recovered data
@@ -767,8 +754,7 @@ variables: []
// Third launch - recovery to workspace-2
const app3 = await launchElectronApp({ userDataPath });
const page3 = await app3.firstWindow();
await page3.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app3);
// Verify workspace-2 created with all data preserved
const ws2 = path.join(userDataPath, 'default-workspace-2');
@@ -798,8 +784,7 @@ variables: []
);
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// Should not crash, new workspace created
const newWorkspace = path.join(userDataPath, 'default-workspace-1');
@@ -822,8 +807,7 @@ variables: []
);
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// Should not crash
expect(fs.existsSync(path.join(userDataPath, 'default-workspace-1'))).toBe(true);
@@ -859,8 +843,7 @@ variables: []
);
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// New workspace should have collection only ONCE (no duplicates)
const newWorkspace = path.join(userDataPath, 'default-workspace-1');
@@ -918,8 +901,7 @@ variables:
);
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await waitForReadyPage(app);
// Check new workspace has the recovered environment (not overwritten by global)
const newWorkspace = path.join(userDataPath, 'default-workspace-1');