From ee80a8dc98d07a35cfe96896eb623fee9b4cd35a Mon Sep 17 00:00:00 2001 From: Curry Yang <1019yanglu@gmail.com> Date: Thu, 12 Feb 2026 15:56:49 +0800 Subject: [PATCH] test: add more case --- packages/insomnia-smoke-test/pages/project.ts | 73 ++++++++++++++ .../insomnia-smoke-test/pages/workspace.ts | 83 +++++++++++++++- .../tests/smoke/export.test.ts | 95 +++++++++++++++++++ 3 files changed, 248 insertions(+), 3 deletions(-) diff --git a/packages/insomnia-smoke-test/pages/project.ts b/packages/insomnia-smoke-test/pages/project.ts index 273a642c2f..d6d9e3734c 100644 --- a/packages/insomnia-smoke-test/pages/project.ts +++ b/packages/insomnia-smoke-test/pages/project.ts @@ -359,4 +359,77 @@ export class ProjectPage { async readFixtureContent(fixturePath: string): Promise { return loadFixture(fixturePath); } + + // ==================== Workspace Export Operations ==================== + + /** + * Opens the workspace card dropdown menu + * @param workspaceName - The name of the workspace + */ + async openWorkspaceCardDropdown(workspaceName: string) { + const workspaceCard = this.getWorkspaceCard(workspaceName); + await workspaceCard.getByLabel('Workspace actions menu button').click(); + } + + /** + * Clicks the Export option in the workspace card dropdown + */ + async clickExportInDropdown() { + await this.page.getByRole('menuitem', { name: 'Export' }).click(); + } + + /** + * Clicks the Export button in the Export Requests modal + */ + async clickExportButtonInExportRequestsModal() { + await this.page.getByRole('dialog').getByRole('button', { name: 'Export' }).click(); + } + + /** + * Selects the export format in the format selection modal + * @param format - The format to select ('yaml' for Insomnia v5, 'har' for HAR) + */ + async selectExportFormat(format: 'yaml' | 'har') { + await this.page.getByText('Which format would you like to export as?').waitFor({ state: 'visible' }); + await this.page.getByLabel('Select Modal').locator('select').selectOption(format); + await this.page.getByRole('button', { name: 'Done' }).click(); + } + + /** + * Mocks the save dialog to return a specific file path + * Used for single file exports from workspace card + * @param filePath - The file path to return + */ + async mockSaveDialogForFile(filePath: string) { + await this.app.evaluate(async ({ ipcMain }, filePath) => { + ipcMain.removeHandler('showSaveDialog'); + ipcMain.handle('showSaveDialog', async () => { + return { filePath, canceled: false }; + }); + }, filePath); + } + + /** + * Exports a workspace from the workspace card dropdown + * Note: After calling this method, use DataPage.waitForExportFiles() to ensure the file is written + * @param workspaceName - The name of the workspace to export + * @param exportPath - The absolute path where the file should be exported + * @param format - The export format ('yaml' or 'har') + */ + async exportWorkspaceFromCard(workspaceName: string, exportPath: string, format: 'yaml' | 'har' = 'yaml') { + // Mock the save dialog first + await this.mockSaveDialogForFile(exportPath); + + // Open workspace card dropdown + await this.openWorkspaceCardDropdown(workspaceName); + + // Click Export option + await this.clickExportInDropdown(); + + // Click Export button in the export requests modal (all requests selected by default) + await this.clickExportButtonInExportRequestsModal(); + + // Select export format + await this.selectExportFormat(format); + } } diff --git a/packages/insomnia-smoke-test/pages/workspace.ts b/packages/insomnia-smoke-test/pages/workspace.ts index d5a69ae1c3..af7b64e061 100644 --- a/packages/insomnia-smoke-test/pages/workspace.ts +++ b/packages/insomnia-smoke-test/pages/workspace.ts @@ -1,14 +1,16 @@ -import type { Page } from '@playwright/test'; +import type { ElectronApplication, Page } from '@playwright/test'; /** * Page Object for the Workspace page (debug view) - * Handles workspace-level operations including navigation + * Handles workspace-level operations including navigation and export */ export class WorkspacePage { readonly page: Page; + readonly app?: ElectronApplication; - constructor(page: Page) { + constructor(page: Page, app?: ElectronApplication) { this.page = page; + this.app = app; } /** @@ -25,4 +27,79 @@ export class WorkspacePage { // Wait for the breadcrumb to be visible, indicating workspace is loaded await this.page.getByTestId('project').waitFor({ state: 'visible' }); } + + // ==================== Export Operations ==================== + + /** + * Opens the workspace dropdown menu + */ + async openWorkspaceDropdown() { + await this.page.getByTestId('workspace-context-dropdown').click(); + } + + /** + * Clicks the Export option in the workspace dropdown + */ + async clickExportInWorkspaceDropdown() { + // Wait for the Export menu item to be visible, then click it + const exportMenuItem = this.page.getByRole('menuitemradio', { name: 'Export' }); + await exportMenuItem.click(); + } + + /** + * Clicks the Export button in the Export Requests modal + */ + async clickExportButtonInExportRequestsModal() { + await this.page.getByRole('dialog').getByRole('button', { name: 'Export' }).click(); + } + + /** + * Selects the export format in the format selection modal + * @param format - The format to select ('yaml' for Insomnia v5, 'har' for HAR) + */ + async selectExportFormat(format: 'yaml' | 'har') { + await this.page.getByText('Which format would you like to export as?').waitFor({ state: 'visible' }); + await this.page.getByLabel('Select Modal').locator('select').selectOption(format); + await this.page.getByRole('button', { name: 'Done' }).click(); + } + + /** + * Mocks the save dialog to return a specific file path + * Used for single file exports from workspace dropdown + * @param filePath - The file path to return + */ + async mockSaveDialogForFile(filePath: string) { + if (!this.app) { + throw new Error('ElectronApplication instance is required for mocking save dialog'); + } + await this.app.evaluate(async ({ ipcMain }, filePath) => { + ipcMain.removeHandler('showSaveDialog'); + ipcMain.handle('showSaveDialog', async () => { + return { filePath, canceled: false }; + }); + }, filePath); + } + + /** + * Exports the workspace from the workspace dropdown + * Note: After calling this method, use DataPage.waitForExportFiles() to ensure the file is written + * @param exportPath - The absolute path where the file should be exported + * @param format - The export format ('yaml' or 'har') + */ + async exportWorkspaceFromDropdown(exportPath: string, format: 'yaml' | 'har' = 'yaml') { + // Mock the save dialog first + await this.mockSaveDialogForFile(exportPath); + + // Open workspace dropdown + await this.openWorkspaceDropdown(); + + // Click Export option + await this.clickExportInWorkspaceDropdown(); + + // Click Export button in the export requests modal (all requests selected by default) + await this.clickExportButtonInExportRequestsModal(); + + // Select export format + await this.selectExportFormat(format); + } } diff --git a/packages/insomnia-smoke-test/tests/smoke/export.test.ts b/packages/insomnia-smoke-test/tests/smoke/export.test.ts index a8298231db..68e089084d 100644 --- a/packages/insomnia-smoke-test/tests/smoke/export.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/export.test.ts @@ -4,6 +4,7 @@ import { expect } from '@playwright/test'; import { DataPage } from '../../pages/preferences/data'; import { ProjectPage } from '../../pages/project'; +import { WorkspacePage } from '../../pages/workspace'; import { test } from '../../playwright/test'; test.describe('Export', () => { @@ -166,4 +167,98 @@ test.describe('Export', () => { dataPage.cleanupExportDir(tempDir); } }); + + test('Can export single workspace from workspace card dropdown', async ({ app, page }) => { + const projectPage = new ProjectPage(page, app); + const workspacePage = new WorkspacePage(page); + const dataPage = new DataPage(page, app); + + const projectName = 'Export Single Workspace Test'; + const fixtureFile = FIXTURE_FILES[0]; // Collection A + + // Step 1: Create a new project + await projectPage.createProject(projectName, 'local'); + + // Wait for empty project view + await projectPage.waitForEmptyProjectView(); + + // Step 2: Import a single fixture file + await projectPage.importFixtureFromEmptyProject(fixtureFile); + + // After import, app redirects to workspace page, navigate back to project + await workspacePage.waitForWorkspaceLoaded(); + await workspacePage.goBackToProject(); + + // Verify collection was imported + const filesGrid = page.getByLabel('Files'); + await expect.soft(filesGrid.getByLabel('Collection A')).toBeVisible(); + + // Step 3: Export workspace from workspace card dropdown + const tempDir = dataPage.createTempExportDir(); + const exportFilePath = path.join(tempDir, 'Collection-A-export.yaml'); + + try { + // Export the workspace using the workspace card dropdown + await projectPage.exportWorkspaceFromCard('Collection A', exportFilePath, 'yaml'); + + // Wait for the export file to be created + await dataPage.waitForExportFiles(tempDir, 1); + + // Step 4: Verify the exported file matches the fixture + const exportedContent = dataPage.readExportedFile(exportFilePath); + + // Compare with fixture + const comparison = dataPage.compareWithFixture(exportedContent, fixtureFile); + + expect.soft(comparison.matches, `Exported file should match fixture ${fixtureFile}`).toBe(true); + } finally { + // Cleanup temp directory + dataPage.cleanupExportDir(tempDir); + } + }); + + test('Can export single workspace from workspace dropdown', async ({ app, page }) => { + const projectPage = new ProjectPage(page, app); + const workspacePage = new WorkspacePage(page, app); + const dataPage = new DataPage(page, app); + + const projectName = 'Export Workspace Dropdown Test'; + const fixtureFile = FIXTURE_FILES[0]; // Collection A + + // Step 1: Create a new project + await projectPage.createProject(projectName, 'local'); + + // Wait for empty project view + await projectPage.waitForEmptyProjectView(); + + // Step 2: Import a single fixture file + await projectPage.importFixtureFromEmptyProject(fixtureFile); + + // After import, app redirects to workspace page + // This time we stay on the workspace page (don't navigate back to project) + await workspacePage.waitForWorkspaceLoaded(); + + // Step 3: Export workspace from workspace dropdown + const tempDir = dataPage.createTempExportDir(); + const exportFilePath = path.join(tempDir, 'Collection-A-workspace-dropdown-export.yaml'); + + try { + // Export the workspace using the workspace dropdown + await workspacePage.exportWorkspaceFromDropdown(exportFilePath, 'yaml'); + + // Wait for the export file to be created + await dataPage.waitForExportFiles(tempDir, 1); + + // Step 4: Verify the exported file matches the fixture + const exportedContent = dataPage.readExportedFile(exportFilePath); + + // Compare with fixture + const comparison = dataPage.compareWithFixture(exportedContent, fixtureFile); + + expect.soft(comparison.matches, `Exported file should match fixture ${fixtureFile}`).toBe(true); + } finally { + // Cleanup temp directory + dataPage.cleanupExportDir(tempDir); + } + }); });