diff --git a/packages/plugin-e2e/src/api.ts b/packages/plugin-e2e/src/api.ts index 463e2ac2c..80103b4c9 100644 --- a/packages/plugin-e2e/src/api.ts +++ b/packages/plugin-e2e/src/api.ts @@ -13,6 +13,7 @@ import { DashboardPageArgs, DashboardEditViewArgs, GotoAppConfigPageArgs, + GotoAppPageArgs, } from './types'; import { PanelEditPage, @@ -22,6 +23,7 @@ import { VariableEditPage, AnnotationEditPage, AppConfigPage, + AppPage, } from './models'; import { grafanaE2ESelectorEngine } from './selectorEngine'; import { ExplorePage } from './models/pages/ExplorePage'; @@ -267,6 +269,11 @@ export type PluginFixture = { * Fixture command that navigates to the AppConfigPage for a given plugin. */ gotoAppConfigPage: (args: GotoAppConfigPageArgs) => Promise; + + /** + * Fixture command that navigates to an AppPage for a given plugin. + */ + gotoAppPage: (args: GotoAppPageArgs) => Promise; }; // extend Playwright with Grafana plugin specific fixtures diff --git a/packages/plugin-e2e/src/fixtures/commands/gotoAppPage.ts b/packages/plugin-e2e/src/fixtures/commands/gotoAppPage.ts new file mode 100644 index 000000000..ec0f9575b --- /dev/null +++ b/packages/plugin-e2e/src/fixtures/commands/gotoAppPage.ts @@ -0,0 +1,19 @@ +import { TestFixture } from '@playwright/test'; +import { PluginFixture, PluginOptions } from '../../api'; +import { PlaywrightCombinedArgs } from '../types'; +import { AppPage, GotoAppPageArgs } from '../..'; + +type GotoAppPageFixture = TestFixture< + (args: GotoAppPageArgs) => Promise, + PluginFixture & PluginOptions & PlaywrightCombinedArgs +>; + +export const gotoAppPage: GotoAppPageFixture = async ({ page, selectors, grafanaVersion, request }, use, testInfo) => { + await use(async ({ pluginId, path }) => { + const appPage = new AppPage({ page, selectors, grafanaVersion, request, testInfo }, { pluginId }); + await appPage.goto({ path }); + return appPage; + }); +}; + +export default gotoAppPage; diff --git a/packages/plugin-e2e/src/fixtures/index.ts b/packages/plugin-e2e/src/fixtures/index.ts index aec0fe47e..e005e7149 100644 --- a/packages/plugin-e2e/src/fixtures/index.ts +++ b/packages/plugin-e2e/src/fixtures/index.ts @@ -19,6 +19,7 @@ import gotoVariableEditPage from './commands/gotoVariableEditPage'; import gotoAnnotationEditPage from './commands/gotoAnnotationEditPage'; import gotoDataSourceConfigPage from './commands/gotoDataSourceConfigPage'; import gotoAppConfigPage from './commands/gotoAppConfigPage'; +import gotoAppPage from './commands/gotoAppPage'; const fixtures = { selectors, @@ -42,6 +43,7 @@ const fixtures = { gotoAnnotationEditPage, gotoDataSourceConfigPage, gotoAppConfigPage, + gotoAppPage, }; export default fixtures; diff --git a/packages/plugin-e2e/src/models/index.ts b/packages/plugin-e2e/src/models/index.ts index 9dc9cd3dd..e4a42d570 100644 --- a/packages/plugin-e2e/src/models/index.ts +++ b/packages/plugin-e2e/src/models/index.ts @@ -12,3 +12,4 @@ export { Panel } from './components/Panel'; export { TimeRange } from './components/TimeRange'; export { AppConfigPage } from './pages/AppConfigPage'; export { PluginConfigPage } from './pages/PluginConfigPage'; +export { AppPage } from './pages/AppPage'; diff --git a/packages/plugin-e2e/src/models/pages/AppConfigPage.ts b/packages/plugin-e2e/src/models/pages/AppConfigPage.ts index ad5a80b99..80ed5355d 100644 --- a/packages/plugin-e2e/src/models/pages/AppConfigPage.ts +++ b/packages/plugin-e2e/src/models/pages/AppConfigPage.ts @@ -1,9 +1,9 @@ import { Response as PlaywrightResponse } from '@playwright/test'; -import { PluginConfigPageArgs, PluginTestCtx } from '../../types'; +import { PluginPageArgs, PluginTestCtx } from '../../types'; import { PluginConfigPage } from './PluginConfigPage'; export class AppConfigPage extends PluginConfigPage { - constructor(readonly ctx: PluginTestCtx, readonly args: PluginConfigPageArgs) { + constructor(readonly ctx: PluginTestCtx, readonly args: PluginPageArgs) { super(ctx, args); } diff --git a/packages/plugin-e2e/src/models/pages/AppPage.ts b/packages/plugin-e2e/src/models/pages/AppPage.ts new file mode 100644 index 000000000..f57822b79 --- /dev/null +++ b/packages/plugin-e2e/src/models/pages/AppPage.ts @@ -0,0 +1,19 @@ +import * as nodePath from 'path'; +import { AppPageNavigateOptions, PluginPageArgs, PluginTestCtx } from '../../types'; +import { GrafanaPage } from '..'; + +export class AppPage extends GrafanaPage { + constructor(readonly ctx: PluginTestCtx, readonly args: PluginPageArgs) { + super(ctx); + } + + /** + * Will append the `/a/${pluginId}` before the provided path and then + * navigate to the page. + */ + goto(options?: AppPageNavigateOptions): Promise { + const path = options?.path ?? ''; + const url = nodePath.join('/a/', this.args.pluginId, path); + return super.navigate(url, options); + } +} diff --git a/packages/plugin-e2e/src/models/pages/PluginConfigPage.ts b/packages/plugin-e2e/src/models/pages/PluginConfigPage.ts index dde0394bd..50b57220c 100644 --- a/packages/plugin-e2e/src/models/pages/PluginConfigPage.ts +++ b/packages/plugin-e2e/src/models/pages/PluginConfigPage.ts @@ -1,9 +1,9 @@ import { Response as PlaywrightResponse } from '@playwright/test'; -import { PluginConfigPageArgs, NavigateOptions, PluginTestCtx } from '../../types'; +import { PluginPageArgs, NavigateOptions, PluginTestCtx } from '../../types'; import { GrafanaPage } from './GrafanaPage'; export class PluginConfigPage extends GrafanaPage { - constructor(readonly ctx: PluginTestCtx, readonly args: PluginConfigPageArgs) { + constructor(readonly ctx: PluginTestCtx, readonly args: PluginPageArgs) { super(ctx); } diff --git a/packages/plugin-e2e/src/types.ts b/packages/plugin-e2e/src/types.ts index 12bb9ae8d..6bd41627c 100644 --- a/packages/plugin-e2e/src/types.ts +++ b/packages/plugin-e2e/src/types.ts @@ -194,6 +194,10 @@ export type NavigateOptions = { queryParams?: URLSearchParams; }; +export type AppPageNavigateOptions = NavigateOptions & { + path?: string; +}; + export type GetByTestIdOrAriaLabelOptions = { /** *Optional root locator to search within. If no locator is provided, the page will be used @@ -304,8 +308,12 @@ export interface ContainTextOptions { useInnerText?: boolean; } -export type PluginConfigPageArgs = { +export type PluginPageArgs = { pluginId: string; }; -export type GotoAppConfigPageArgs = PluginConfigPageArgs; +export type GotoAppConfigPageArgs = PluginPageArgs; + +export type GotoAppPageArgs = PluginPageArgs & { + path?: string; +}; diff --git a/packages/plugin-e2e/tests/as-admin-user/app/app-page/app-page.spec.ts b/packages/plugin-e2e/tests/as-admin-user/app/app-page/app-page.spec.ts new file mode 100644 index 000000000..ac22a7463 --- /dev/null +++ b/packages/plugin-e2e/tests/as-admin-user/app/app-page/app-page.spec.ts @@ -0,0 +1,25 @@ +import { AppPage, expect, test } from '../../../../src'; + +test('should navigate to app root page when calling goto without any path', async ({ + grafanaVersion, + selectors, + page, + request, +}, testInfo) => { + const appPage = new AppPage({ grafanaVersion, selectors, page, request, testInfo }, { pluginId: 'redis-app' }); + await appPage.goto(); + + await expect(page).toHaveURL(/.*\/a\/redis-app$/); +}); + +test('should navigate to app sub page when calling goto with path', async ({ + grafanaVersion, + selectors, + page, + request, +}, testInfo) => { + const appPage = new AppPage({ grafanaVersion, selectors, page, request, testInfo }, { pluginId: 'redis-app' }); + await appPage.goto({ path: '/create' }); + + await expect(page).toHaveURL(/.*\/a\/redis-app\/create$/); +}); diff --git a/packages/plugin-e2e/tests/as-admin-user/app/app-page/goto-app-page.spec.ts b/packages/plugin-e2e/tests/as-admin-user/app/app-page/goto-app-page.spec.ts new file mode 100644 index 000000000..25022c0f0 --- /dev/null +++ b/packages/plugin-e2e/tests/as-admin-user/app/app-page/goto-app-page.spec.ts @@ -0,0 +1,11 @@ +import { expect, test } from '../../../../src'; + +test('should navigate to app root page when calling goto without any path', async ({ gotoAppPage, page }) => { + await gotoAppPage({ pluginId: 'redis-app' }); + await expect(page).toHaveURL(/.*\/a\/redis-app$/); +}); + +test('should navigate to app sub page when calling goto with path', async ({ gotoAppPage, page }) => { + await gotoAppPage({ pluginId: 'redis-app', path: '/create' }); + await expect(page).toHaveURL(/.*\/a\/redis-app\/create$/); +});