From eb56ef8c43bede0d624e9373583349a574d8b5f1 Mon Sep 17 00:00:00 2001 From: Alexandre Neuwald CTW Date: Mon, 22 Apr 2024 09:38:51 +0100 Subject: [PATCH 1/3] Fix integration tests --- desktop/integration-test/menus.test.ts | 59 +++++++++---------- .../src/components/AppBar/AppMenu.tsx | 3 + .../src/components/AppBar/NestedMenuItem.tsx | 1 + .../src/components/AppBar/index.tsx | 1 + .../src/components/AppBar/types.ts | 1 + .../DataSourceDialog/DataSourceDialog.tsx | 2 +- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/desktop/integration-test/menus.test.ts b/desktop/integration-test/menus.test.ts index 0b4c64b7f1..5cae2ecf76 100644 --- a/desktop/integration-test/menus.test.ts +++ b/desktop/integration-test/menus.test.ts @@ -4,43 +4,44 @@ import { signal } from "@foxglove/den/async"; -import { launchApp } from "./launchApp"; +import { AppType, launchApp } from "./launchApp"; describe("menus", () => { - it("should display the data source dialog when clicking File > Open", async () => { - await using app = await launchApp(); - // The Open dialog shows up automatically; close it + const closeDataSourceDialogAfterAppLaunch = async (app: AppType) => { await expect(app.renderer.getByTestId("DataSourceDialog").isVisible()).resolves.toBe(true); await app.renderer.getByTestId("DataSourceDialog").getByTestId("CloseIcon").click(); - await expect(app.renderer.getByTestId("DataSourceDialog").count()).resolves.toBe(0); + await expect(app.renderer.getByTestId("DataSourceDialog").isVisible()).resolves.toBe(false); + }; - // Click "File > Open" and the dialog should appear again - await app.main.evaluate(async ({ Menu }) => { - const menu = Menu.getApplicationMenu(); - menu?.getMenuItemById("fileMenu")?.submenu?.getMenuItemById("open")?.click(); - }); - await app.renderer.waitForSelector('[data-testid="DataSourceDialog"]', { state: "visible" }); - }, 15_000); + it("should display the data source dialog when clicking File > Open", async () => { + await using app = await launchApp(); + + await closeDataSourceDialogAfterAppLaunch(app); + + await app.renderer.getByTestId("AppMenuButton").click(); + await app.renderer.getByTestId("app-menu-file").click(); + await app.renderer.getByTestId("menu-item-open").click(); + + await expect(app.renderer.getByTestId("DataSourceDialog").isVisible()).resolves.toBe(true); + }); it("should display the Open Connection screen when clicking File > Open Connection", async () => { await using app = await launchApp(); - // The Open dialog shows up automatically; close it - await expect(app.renderer.getByTestId("DataSourceDialog").isVisible()).resolves.toBe(true); - await expect(app.renderer.getByTestId("OpenConnection").count()).resolves.toBe(0); - await app.renderer.getByTestId("DataSourceDialog").getByTestId("CloseIcon").click(); - await expect(app.renderer.getByTestId("DataSourceDialog").count()).resolves.toBe(0); - // Click "File > Open Connection" and the Open Connection screen should appear - await app.main.evaluate(async ({ Menu }) => { - const menu = Menu.getApplicationMenu(); - menu?.getMenuItemById("fileMenu")?.submenu?.getMenuItemById("openConnection")?.click(); - }); - await app.renderer.waitForSelector('[data-testid="OpenConnection"]', { state: "visible" }); - }, 15_000); + await closeDataSourceDialogAfterAppLaunch(app); + + await app.renderer.getByTestId("AppMenuButton").click(); + await app.renderer.getByTestId("app-menu-file").click(); + await app.renderer.getByTestId("menu-item-open-connection").click(); + + await expect(app.renderer.getByTestId("OpenConnection").count()).resolves.toBe(1); + }); it("should open the file chooser when clicking File > Open Local File", async () => { await using app = await launchApp(); + await closeDataSourceDialogAfterAppLaunch(app); + // The page is loaded as a file:// URL in the test, so showOpenFilePicker is not available and we need to mock it. // If it were available we could use `app.renderer.waitForEvent("filechooser")` instead. const openFilePickerCalled = signal(); @@ -49,12 +50,10 @@ describe("menus", () => { return []; }); - // Click "File > Open Connection" and the Open Connection screen should appear - await app.main.evaluate(async ({ Menu }) => { - const menu = Menu.getApplicationMenu(); - menu?.getMenuItemById("fileMenu")?.submenu?.getMenuItemById("openLocalFile")?.click(); - }); + await app.renderer.getByTestId("AppMenuButton").click(); + await app.renderer.getByTestId("app-menu-file").click(); + await app.renderer.getByTestId("menu-item-open-local-file").click(); await expect(openFilePickerCalled).resolves.toBe(true); - }, 15_000); + }); }); diff --git a/packages/studio-base/src/components/AppBar/AppMenu.tsx b/packages/studio-base/src/components/AppBar/AppMenu.tsx index 09e1b71397..2f527fc6b0 100644 --- a/packages/studio-base/src/components/AppBar/AppMenu.tsx +++ b/packages/studio-base/src/components/AppBar/AppMenu.tsx @@ -70,6 +70,7 @@ export function AppMenu(props: AppMenuProps): JSX.Element { type: "item", label: t("open"), key: "open", + dataTestId: "menu-item-open", onClick: () => { dialogActions.dataSource.open("start"); handleNestedMenuClose(); @@ -79,6 +80,7 @@ export function AppMenu(props: AppMenuProps): JSX.Element { type: "item", label: t("openLocalFile"), key: "open-file", + dataTestId: "menu-item-open-local-file", onClick: () => { handleNestedMenuClose(); dialogActions.openFile.open().catch(console.error); @@ -88,6 +90,7 @@ export function AppMenu(props: AppMenuProps): JSX.Element { type: "item", label: t("openConnection"), key: "open-connection", + dataTestId: "menu-item-open-connection", onClick: () => { dialogActions.dataSource.open("connection"); handleNestedMenuClose(); diff --git a/packages/studio-base/src/components/AppBar/NestedMenuItem.tsx b/packages/studio-base/src/components/AppBar/NestedMenuItem.tsx index 2ae5c80a88..d24331ef85 100644 --- a/packages/studio-base/src/components/AppBar/NestedMenuItem.tsx +++ b/packages/studio-base/src/components/AppBar/NestedMenuItem.tsx @@ -104,6 +104,7 @@ export function NestedMenuItem( className={classes.menuItem} key={item.key} onClick={item.onClick} + data-testid={item.dataTestId} disabled={item.disabled} > {item.label} diff --git a/packages/studio-base/src/components/AppBar/index.tsx b/packages/studio-base/src/components/AppBar/index.tsx index 95e80b6db6..7bed6be3a3 100644 --- a/packages/studio-base/src/components/AppBar/index.tsx +++ b/packages/studio-base/src/components/AppBar/index.tsx @@ -198,6 +198,7 @@ export function AppBar(props: AppBarProps): JSX.Element { className={cx(classes.logo, { "Mui-selected": appMenuOpen })} color="inherit" id="app-menu-button" + data-testid="AppMenuButton" title="Menu" aria-controls={appMenuOpen ? "app-menu" : undefined} aria-haspopup="true" diff --git a/packages/studio-base/src/components/AppBar/types.ts b/packages/studio-base/src/components/AppBar/types.ts index 5da5c38f6d..d89d08a200 100644 --- a/packages/studio-base/src/components/AppBar/types.ts +++ b/packages/studio-base/src/components/AppBar/types.ts @@ -17,6 +17,7 @@ export type AppBarMenuItem = onClick?: MouseEventHandler; external?: boolean; icon?: ReactNode; + dataTestId?: string; } | { type: "subheader"; label: ReactNode; key: string } | { type: "divider" }; diff --git a/packages/studio-base/src/components/DataSourceDialog/DataSourceDialog.tsx b/packages/studio-base/src/components/DataSourceDialog/DataSourceDialog.tsx index 934c6fe3cd..1f8dce0eb8 100644 --- a/packages/studio-base/src/components/DataSourceDialog/DataSourceDialog.tsx +++ b/packages/studio-base/src/components/DataSourceDialog/DataSourceDialog.tsx @@ -135,7 +135,7 @@ export function DataSourceDialog(props: DataSourceDialogProps): JSX.Element { }} > - + Date: Mon, 22 Apr 2024 09:51:28 +0100 Subject: [PATCH 2/3] Export AppType for tests --- desktop/integration-test/launchApp.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/desktop/integration-test/launchApp.ts b/desktop/integration-test/launchApp.ts index 6adc68cfbd..d8ccb43dee 100644 --- a/desktop/integration-test/launchApp.ts +++ b/desktop/integration-test/launchApp.ts @@ -20,17 +20,17 @@ import { appPath } from "./build"; const log = Logger.getLogger(__filename); +export type AppType = { + main: ElectronApplication; + renderer: Page; +} & AsyncDisposable; + /** * Launch the app and wait for initial render. * * @returns An AsyncDisposable which automatically closes the app when it goes out of scope. */ -export async function launchApp(): Promise< - { - main: ElectronApplication; - renderer: Page; - } & AsyncDisposable -> { +export async function launchApp(): Promise { // Create a new user data directory for each test, which bypasses the `app.requestSingleInstanceLock()` const userDataDir = await mkdtemp(path.join(os.tmpdir(), "integration-test-")); const electronApp = await electron.launch({ From 9ce30b74e3e6e5a5da76ebe7183fc18d44b5d1ad Mon Sep 17 00:00:00 2001 From: Alexandre Neuwald CTW Date: Mon, 22 Apr 2024 10:02:44 +0100 Subject: [PATCH 3/3] Raise timeout limit for the tests --- desktop/integration-test/menus.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/desktop/integration-test/menus.test.ts b/desktop/integration-test/menus.test.ts index 5cae2ecf76..51ac6a66e0 100644 --- a/desktop/integration-test/menus.test.ts +++ b/desktop/integration-test/menus.test.ts @@ -23,7 +23,7 @@ describe("menus", () => { await app.renderer.getByTestId("menu-item-open").click(); await expect(app.renderer.getByTestId("DataSourceDialog").isVisible()).resolves.toBe(true); - }); + }, 15_000); it("should display the Open Connection screen when clicking File > Open Connection", async () => { await using app = await launchApp(); @@ -35,7 +35,7 @@ describe("menus", () => { await app.renderer.getByTestId("menu-item-open-connection").click(); await expect(app.renderer.getByTestId("OpenConnection").count()).resolves.toBe(1); - }); + }, 15_000); it("should open the file chooser when clicking File > Open Local File", async () => { await using app = await launchApp(); @@ -55,5 +55,5 @@ describe("menus", () => { await app.renderer.getByTestId("menu-item-open-local-file").click(); await expect(openFilePickerCalled).resolves.toBe(true); - }); + }, 15_000); });