diff --git a/jest.config.e2e.js b/jest.config.e2e.js index feb6f7d4f3a..8b3eb4ee732 100644 --- a/jest.config.e2e.js +++ b/jest.config.e2e.js @@ -11,5 +11,5 @@ module.exports = { moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], setupFiles: [], globals: { 'ts-jest': { isolatedModules: true } }, - setupFilesAfterEnv: ['expect-puppeteer', '/public/e2e-test/install/install.ts'], -}; + setupFilesAfterEnv: ['expect-puppeteer', '/packages/grafana-toolkit/src/e2e/install.ts'], +}; \ No newline at end of file diff --git a/packages/grafana-toolkit/package.json b/packages/grafana-toolkit/package.json index ab2ba692124..86eab1fb85c 100644 --- a/packages/grafana-toolkit/package.json +++ b/packages/grafana-toolkit/package.json @@ -19,14 +19,17 @@ }, "author": "Grafana Labs", "license": "Apache-2.0", + "main": "src/index.ts", "dependencies": { "@babel/core": "7.4.5", "@babel/preset-env": "7.4.5", "@types/execa": "^0.9.0", + "@types/expect-puppeteer": "3.3.1", "@types/inquirer": "^6.0.3", "@types/jest": "24.0.13", "@types/jest-cli": "^23.6.0", "@types/node": "^12.0.4", + "@types/puppeteer-core": "1.9.0", "@types/react-dev-utils": "^9.0.1", "@types/semver": "^6.0.0", "@types/tmp": "^0.1.0", @@ -40,6 +43,7 @@ "copy-webpack-plugin": "5.0.3", "css-loader": "^3.0.0", "execa": "^1.0.0", + "expect-puppeteer": "4.1.1", "file-loader": "^4.0.0", "glob": "^7.1.4", "html-loader": "0.5.5", @@ -57,6 +61,7 @@ "postcss-loader": "3.0.0", "postcss-preset-env": "6.6.0", "prettier": "^1.18.2", + "puppeteer-core": "1.18.1", "react-dev-utils": "^9.0.1", "replace-in-file": "^4.1.0", "replace-in-file-webpack-plugin": "^1.0.6", @@ -78,5 +83,8 @@ "devDependencies": { "@types/glob": "^7.1.1", "@types/prettier": "^1.16.4" + }, + "_moduleAliases": { + "puppeteer": "node_modules/puppeteer-core" } } diff --git a/public/e2e-test/core/constants.ts b/packages/grafana-toolkit/src/e2e/constants.ts similarity index 100% rename from public/e2e-test/core/constants.ts rename to packages/grafana-toolkit/src/e2e/constants.ts diff --git a/public/e2e-test/core/images.ts b/packages/grafana-toolkit/src/e2e/images.ts similarity index 79% rename from public/e2e-test/core/images.ts rename to packages/grafana-toolkit/src/e2e/images.ts index 2897ba8aa2d..752b5ad67d0 100644 --- a/public/e2e-test/core/images.ts +++ b/packages/grafana-toolkit/src/e2e/images.ts @@ -25,17 +25,17 @@ export const compareScreenShots = async (fileName: string) => if (screenShotFromTest.width !== screenShotFromTruth.width) { throw new Error( - `The screenshot:[${fileName}] taken during the test has a width:[${ - screenShotFromTest.width - }] that differs from the expected: [${screenShotFromTruth.width}].` + `The screenshot:[${fileName}] taken during the test has a ` + + `width:[${screenShotFromTest.width}] that differs from the ` + + `expected: [${screenShotFromTruth.width}].` ); } if (screenShotFromTest.height !== screenShotFromTruth.height) { throw new Error( - `The screenshot:[${fileName}] taken during the test has a width:[${ - screenShotFromTest.height - }] that differs from the expected: [${screenShotFromTruth.height}].` + `The screenshot:[${fileName}] taken during the test has a ` + + `height:[${screenShotFromTest.height}] that differs from the ` + + `expected: [${screenShotFromTruth.height}].` ); } @@ -50,14 +50,14 @@ export const compareScreenShots = async (fileName: string) => ); if (numDiffPixels !== 0) { - const localMessage = `\nCompare the output from expected:[${constants.screenShotsTruthDir}] with outcome:[${ - constants.screenShotsOutputDir - }]`; + const localMessage = + `\nCompare the output from expected:[${constants.screenShotsTruthDir}] ` + + `with outcome:[${constants.screenShotsOutputDir}]`; const circleCIMessage = '\nCheck the Artifacts tab in the CircleCi build output for the actual screenshots.'; const checkMessage = process.env.CIRCLE_SHA1 ? circleCIMessage : localMessage; - let msg = `\nThe screenshot:[${ - constants.screenShotsOutputDir - }/${fileName}.png] taken during the test differs by:[${numDiffPixels}] pixels from the expected.`; + let msg = + `\nThe screenshot:[${constants.screenShotsOutputDir}/${fileName}.png] ` + + `taken during the test differs by:[${numDiffPixels}] pixels from the expected.`; msg += '\n'; msg += checkMessage; msg += '\n'; diff --git a/packages/grafana-toolkit/src/e2e/index.ts b/packages/grafana-toolkit/src/e2e/index.ts new file mode 100644 index 00000000000..03a15556162 --- /dev/null +++ b/packages/grafana-toolkit/src/e2e/index.ts @@ -0,0 +1,8 @@ +export * from './constants'; +export * from './images'; +export * from './install'; +export * from './launcher'; +export * from './login'; +export * from './pageObjects'; +export * from './pages'; +export * from './scenario'; diff --git a/public/e2e-test/install/install.ts b/packages/grafana-toolkit/src/e2e/install.ts similarity index 93% rename from public/e2e-test/install/install.ts rename to packages/grafana-toolkit/src/e2e/install.ts index 61bfca0bfca..1dc2f943a26 100644 --- a/public/e2e-test/install/install.ts +++ b/packages/grafana-toolkit/src/e2e/install.ts @@ -1,5 +1,5 @@ import puppeteer from 'puppeteer-core'; -import { constants } from 'e2e-test/core/constants'; +import { constants } from './constants'; export const downloadBrowserIfNeeded = async (): Promise => { const browserFetcher = puppeteer.createBrowserFetcher(); diff --git a/public/e2e-test/core/launcher.ts b/packages/grafana-toolkit/src/e2e/launcher.ts similarity index 100% rename from public/e2e-test/core/launcher.ts rename to packages/grafana-toolkit/src/e2e/launcher.ts diff --git a/public/e2e-test/core/login.ts b/packages/grafana-toolkit/src/e2e/login.ts similarity index 68% rename from public/e2e-test/core/login.ts rename to packages/grafana-toolkit/src/e2e/login.ts index bdf57e38424..99890d45abd 100644 --- a/public/e2e-test/core/login.ts +++ b/packages/grafana-toolkit/src/e2e/login.ts @@ -1,15 +1,15 @@ import { Page } from 'puppeteer-core'; import { constants } from './constants'; -import { loginPage } from 'e2e-test/pages/start/loginPage'; +import { loginPage } from './start/loginPage'; export const login = async (page: Page) => { await loginPage.init(page); await loginPage.navigateTo(); - await loginPage.pageObjects.username.enter('admin'); - await loginPage.pageObjects.password.enter('admin'); - await loginPage.pageObjects.submit.click(); + await loginPage.pageObjects!.username.enter('admin'); + await loginPage.pageObjects!.password.enter('admin'); + await loginPage.pageObjects!.submit.click(); await loginPage.waitForResponse(); }; diff --git a/public/e2e-test/core/pageObjects.ts b/packages/grafana-toolkit/src/e2e/pageObjects.ts similarity index 96% rename from public/e2e-test/core/pageObjects.ts rename to packages/grafana-toolkit/src/e2e/pageObjects.ts index 97fb65eb7ab..4c9c77e0a8c 100644 --- a/public/e2e-test/core/pageObjects.ts +++ b/packages/grafana-toolkit/src/e2e/pageObjects.ts @@ -29,7 +29,7 @@ export interface SelectPageObjectType extends PageObjectType { } export class PageObject implements PageObjectType { - protected page: Page = null; + protected page?: Page; constructor(protected selector: string) {} @@ -82,6 +82,6 @@ export class SelectPageObject extends PageObject implements SelectPageObjectType select = async (text: string): Promise => { console.log(`Trying to select text:${text} in dropdown:`, this.selector); await expect(this.page).not.toBeNull(); - await this.page.select(this.selector, text); + await this.page!.select(this.selector, text); }; } diff --git a/public/e2e-test/core/pages.ts b/packages/grafana-toolkit/src/e2e/pages.ts similarity index 83% rename from public/e2e-test/core/pages.ts rename to packages/grafana-toolkit/src/e2e/pages.ts index 48124f61d30..c7b7031a50a 100644 --- a/public/e2e-test/core/pages.ts +++ b/packages/grafana-toolkit/src/e2e/pages.ts @@ -17,7 +17,8 @@ export interface TestPageType { waitForResponse: () => Promise; waitForNavigation: () => Promise; waitFor: (milliseconds: number) => Promise; - pageObjects: PageObjects; + + pageObjects?: PageObjects; } type PageObjects = { [P in keyof T]: T[P] }; @@ -28,17 +29,15 @@ export interface TestPageConfig { } export class TestPage implements TestPageType { - pageObjects: PageObjects = null; - private page: Page = null; - private pageUrl: string = null; + pageObjects?: PageObjects; + private page?: Page; + private pageUrl?: string; constructor(config: TestPageConfig) { if (config.url) { this.pageUrl = `${constants.baseUrl}${config.url}`; } - if (config.pageObjects) { - this.pageObjects = config.pageObjects; - } + this.pageObjects = config.pageObjects; } init = async (page: Page): Promise => { @@ -59,7 +58,7 @@ export class TestPage implements TestPageType { this.throwIfNotInitialized(); console.log('Trying to navigate to:', this.pageUrl); - await this.page.goto(this.pageUrl); + await this.page!.goto(this.pageUrl!); }; expectSelector = async (config: ExpectSelectorConfig): Promise => { @@ -75,19 +74,19 @@ export class TestPage implements TestPageType { waitForResponse = async (): Promise => { this.throwIfNotInitialized(); - await this.page.waitForResponse(response => response.url() === this.pageUrl && response.status() === 200); + await this.page!.waitForResponse(response => response.url() === this.pageUrl && response.status() === 200); }; waitForNavigation = async (): Promise => { this.throwIfNotInitialized(); - await this.page.waitForNavigation(); + await this.page!.waitForNavigation(); }; getUrl = async (): Promise => { this.throwIfNotInitialized(); - return await this.page.url(); + return await this.page!.url(); }; getUrlWithoutBaseUrl = async (): Promise => { @@ -101,7 +100,7 @@ export class TestPage implements TestPageType { waitFor = async (milliseconds: number) => { this.throwIfNotInitialized(); - await this.page.waitFor(milliseconds); + await this.page!.waitFor(milliseconds); }; private throwIfNotInitialized = () => { diff --git a/public/e2e-test/core/scenario.ts b/packages/grafana-toolkit/src/e2e/scenario.ts similarity index 91% rename from public/e2e-test/core/scenario.ts rename to packages/grafana-toolkit/src/e2e/scenario.ts index a16f1e467ce..4691ac15609 100644 --- a/public/e2e-test/core/scenario.ts +++ b/packages/grafana-toolkit/src/e2e/scenario.ts @@ -8,8 +8,8 @@ export const e2eScenario = ( callback: (browser: Browser, page: Page) => void ) => { describe(title, () => { - let browser: Browser = null; - let page: Page = null; + let browser: Browser; + let page: Page; beforeAll(async () => { browser = await launchBrowser(); diff --git a/public/e2e-test/pages/start/loginPage.ts b/packages/grafana-toolkit/src/e2e/start/loginPage.ts similarity index 87% rename from public/e2e-test/pages/start/loginPage.ts rename to packages/grafana-toolkit/src/e2e/start/loginPage.ts index 7d4d31b8506..4478ae534e5 100644 --- a/public/e2e-test/pages/start/loginPage.ts +++ b/packages/grafana-toolkit/src/e2e/start/loginPage.ts @@ -1,11 +1,11 @@ +import { TestPage } from '../pages'; import { - InputPageObject, - ClickablePageObject, Selector, + InputPageObject, InputPageObjectType, ClickablePageObjectType, -} from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; + ClickablePageObject, +} from '../pageObjects'; export interface LoginPage { username: InputPageObjectType; diff --git a/packages/grafana-toolkit/src/index.ts b/packages/grafana-toolkit/src/index.ts new file mode 100644 index 00000000000..8bc64fdd742 --- /dev/null +++ b/packages/grafana-toolkit/src/index.ts @@ -0,0 +1 @@ +export * from './e2e'; diff --git a/public/e2e-test/pages/dashboards/createDashboardPage.ts b/public/e2e-test/pages/dashboards/createDashboardPage.ts index de6a0b36bff..ba312c038f9 100644 --- a/public/e2e-test/pages/dashboards/createDashboardPage.ts +++ b/public/e2e-test/pages/dashboards/createDashboardPage.ts @@ -1,5 +1,4 @@ -import { ClickablePageObjectType, ClickablePageObject, Selector } from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +import { TestPage, ClickablePageObjectType, ClickablePageObject, Selector } from '@grafana/toolkit'; export interface CreateDashboardPage { addQuery: ClickablePageObjectType; diff --git a/public/e2e-test/pages/dashboards/dashboardsPage.ts b/public/e2e-test/pages/dashboards/dashboardsPage.ts index be14e5e23ce..67b525e5932 100644 --- a/public/e2e-test/pages/dashboards/dashboardsPage.ts +++ b/public/e2e-test/pages/dashboards/dashboardsPage.ts @@ -1,5 +1,4 @@ -import { ClickablePageObjectType, ClickablePageObject, Selector } from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +import { TestPage, ClickablePageObjectType, ClickablePageObject, Selector } from '@grafana/toolkit'; export interface DashboardsPage { dashboard: ClickablePageObjectType; diff --git a/public/e2e-test/pages/dashboards/saveDashboardModal.ts b/public/e2e-test/pages/dashboards/saveDashboardModal.ts index d69bbe1a8cd..6d0ea6163e8 100644 --- a/public/e2e-test/pages/dashboards/saveDashboardModal.ts +++ b/public/e2e-test/pages/dashboards/saveDashboardModal.ts @@ -1,12 +1,12 @@ import { + TestPage, ClickablePageObjectType, ClickablePageObject, Selector, InputPageObjectType, InputPageObject, PageObject, -} from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +} from '@grafana/toolkit'; export interface SaveDashboardModal { name: InputPageObjectType; diff --git a/public/e2e-test/pages/datasources/addDataSourcePage.ts b/public/e2e-test/pages/datasources/addDataSourcePage.ts index 9ae8972f542..cf7cbcf6249 100644 --- a/public/e2e-test/pages/datasources/addDataSourcePage.ts +++ b/public/e2e-test/pages/datasources/addDataSourcePage.ts @@ -1,5 +1,4 @@ -import { ClickablePageObject, Selector, ClickablePageObjectType } from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +import { TestPage, ClickablePageObject, Selector, ClickablePageObjectType } from '@grafana/toolkit'; export interface AddDataSourcePage { testDataDB: ClickablePageObjectType; diff --git a/public/e2e-test/pages/datasources/dataSources.ts b/public/e2e-test/pages/datasources/dataSources.ts index 114b3017abf..b76625e1c1c 100644 --- a/public/e2e-test/pages/datasources/dataSources.ts +++ b/public/e2e-test/pages/datasources/dataSources.ts @@ -1,4 +1,4 @@ -import { TestPage } from 'e2e-test/core/pages'; +import { TestPage } from '@grafana/toolkit'; export interface DataSourcesPage {} diff --git a/public/e2e-test/pages/datasources/editDataSourcePage.ts b/public/e2e-test/pages/datasources/editDataSourcePage.ts index 9e9dd58dd8c..d508789ecc1 100644 --- a/public/e2e-test/pages/datasources/editDataSourcePage.ts +++ b/public/e2e-test/pages/datasources/editDataSourcePage.ts @@ -1,11 +1,11 @@ import { + TestPage, ClickablePageObjectType, PageObjectType, ClickablePageObject, PageObject, Selector, -} from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +} from '@grafana/toolkit'; export interface EditDataSourcePage { saveAndTest: ClickablePageObjectType; diff --git a/public/e2e-test/pages/panels/editPanel.ts b/public/e2e-test/pages/panels/editPanel.ts index ff1263baa2e..4bc6f8f0470 100644 --- a/public/e2e-test/pages/panels/editPanel.ts +++ b/public/e2e-test/pages/panels/editPanel.ts @@ -1,11 +1,11 @@ import { + TestPage, SelectPageObjectType, SelectPageObject, Selector, ClickablePageObjectType, ClickablePageObject, -} from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +} from '@grafana/toolkit'; export interface EditPanelPage { queriesTab: ClickablePageObjectType; @@ -20,7 +20,9 @@ export const editPanelPage = new TestPage({ queriesTab: new ClickablePageObject(Selector.fromAriaLabel('Queries tab button')), saveDashboard: new ClickablePageObject(Selector.fromAriaLabel('Save dashboard navbar button')), scenarioSelect: new SelectPageObject(Selector.fromAriaLabel('Scenario Select')), - showXAxis: new ClickablePageObject(Selector.fromSelector('[aria-label="X-Axis section"] > gf-form-switch')), + showXAxis: new ClickablePageObject( + Selector.fromSelector('[aria-label="X-Axis section"] [label=Show] .gf-form-switch') + ), visualizationTab: new ClickablePageObject(Selector.fromAriaLabel('Visualization tab button')), }, }); diff --git a/public/e2e-test/pages/panels/panel.ts b/public/e2e-test/pages/panels/panel.ts index 6a59c0d6f2b..78a35b96349 100644 --- a/public/e2e-test/pages/panels/panel.ts +++ b/public/e2e-test/pages/panels/panel.ts @@ -1,5 +1,4 @@ -import { ClickablePageObjectType, ClickablePageObject, Selector } from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +import { TestPage, ClickablePageObjectType, ClickablePageObject, Selector } from '@grafana/toolkit'; export interface Panel { panelTitle: ClickablePageObjectType; diff --git a/public/e2e-test/pages/panels/sharePanelModal.ts b/public/e2e-test/pages/panels/sharePanelModal.ts index 3ead88ad536..c8dd1e1fb47 100644 --- a/public/e2e-test/pages/panels/sharePanelModal.ts +++ b/public/e2e-test/pages/panels/sharePanelModal.ts @@ -1,5 +1,4 @@ -import { ClickablePageObjectType, ClickablePageObject, Selector } from 'e2e-test/core/pageObjects'; -import { TestPage } from 'e2e-test/core/pages'; +import { TestPage, ClickablePageObjectType, ClickablePageObject, Selector } from '@grafana/toolkit'; export interface SharePanelModal { directLinkRenderedImage: ClickablePageObjectType; diff --git a/public/e2e-test/scenarios/smoke.test.ts b/public/e2e-test/scenarios/smoke.test.ts index ff28bfafb5f..85740a7a770 100644 --- a/public/e2e-test/scenarios/smoke.test.ts +++ b/public/e2e-test/scenarios/smoke.test.ts @@ -1,6 +1,6 @@ import { Browser, Page, Target } from 'puppeteer-core'; -import { e2eScenario } from 'e2e-test/core/scenario'; +import { e2eScenario, constants, takeScreenShot, compareScreenShots } from '@grafana/toolkit'; import { addDataSourcePage } from 'e2e-test/pages/datasources/addDataSourcePage'; import { editDataSourcePage } from 'e2e-test/pages/datasources/editDataSourcePage'; import { dataSourcesPage } from 'e2e-test/pages/datasources/dataSources'; @@ -9,9 +9,7 @@ import { saveDashboardModal } from 'e2e-test/pages/dashboards/saveDashboardModal import { dashboardsPageFactory } from 'e2e-test/pages/dashboards/dashboardsPage'; import { panel } from 'e2e-test/pages/panels/panel'; import { editPanelPage } from 'e2e-test/pages/panels/editPanel'; -import { constants } from 'e2e-test/core/constants'; import { sharePanelModal } from 'e2e-test/pages/panels/sharePanelModal'; -import { takeScreenShot, compareScreenShots } from 'e2e-test/core/images'; e2eScenario( 'Login scenario, create test data source, dashboard, panel, and export scenario',