From edea96f3a3d49424f7b625cc111249129865fccb Mon Sep 17 00:00:00 2001 From: Adam Yeats Date: Mon, 2 Oct 2023 17:16:12 +0200 Subject: [PATCH] WIP: E2E comparison --- .github/workflows/cypress.yml | 15 +++- .github/workflows/k6.yml | 19 ++++- .github/workflows/playwright.yml | 76 +++++++++++------- .github/workflows/pull-request-image.yml | 2 + e2e/k6/{k6.test.js => k6.spec.js} | 8 +- e2e/playwright/playwright.spec.ts | 99 ++++++++++++++---------- package.json | 6 +- 7 files changed, 139 insertions(+), 86 deletions(-) rename e2e/k6/{k6.test.js => k6.spec.js} (97%) diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index a33a042c0..70b00402f 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -2,14 +2,16 @@ name: E2E tests - Cypress on: [push, pull_request] jobs: - build: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Use Node.js + + - name: Setup Node.js environment uses: actions/setup-node@v3 with: node-version-file: .nvmrc + - name: Install yarn dependencies run: yarn install env: @@ -22,5 +24,14 @@ jobs: run: yarn build env: NODE_OPTIONS: '--max_old_space_size=4096' + - name: Start Grafana run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD:/var/lib/grafana/plugins" grafana/grafana + + - name: Run E2E tests + run: yarn run e2e + env: + E2E_ADX_CLIENT_ID: ${{ secrets.E2E_ADX_CLIENT_ID }} + E2E_ADX_CLIENT_SECRET: ${{ secrets.E2E_ADX_CLIENT_SECRET }} + E2E_ADX_CLUSTER_URL: ${{ secrets.E2E_ADX_CLUSTER_URL }} + E2E_ADX_TENANT_ID: ${{ secrets.E2E_ADX_TENANT_ID }} diff --git a/.github/workflows/k6.yml b/.github/workflows/k6.yml index 8a40a3594..c13147dbc 100644 --- a/.github/workflows/k6.yml +++ b/.github/workflows/k6.yml @@ -2,14 +2,16 @@ name: E2E tests - k6 on: [push, pull_request] jobs: - build: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Use Node.js uses: actions/setup-node@v3 with: node-version-file: .nvmrc + - name: Install yarn dependencies run: yarn install env: @@ -22,6 +24,7 @@ jobs: run: yarn build env: NODE_OPTIONS: '--max_old_space_size=4096' + - name: Setup k6 run: | sudo gpg -k @@ -29,7 +32,15 @@ jobs: echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list sudo apt-get update sudo apt-get install k6 + - name: Start Grafana - run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD:/var/lib/grafana/plugins" grafana/grafana - - name: Run e2e tests - run: k6 run ./e2e/k6/k6.test.js + run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD/dist:/var/lib/grafana/plugins/azure-data-explorer-datasource" grafana/grafana; sleep 30 + + - name: Run E2E tests + run: k6 run ./e2e/k6/k6.spec.js + env: + E2E_ADX_CLIENT_ID: ${{ secrets.E2E_ADX_CLIENT_ID }} + E2E_ADX_CLIENT_SECRET: ${{ secrets.E2E_ADX_CLIENT_SECRET }} + E2E_ADX_CLUSTER_URL: ${{ secrets.E2E_ADX_CLUSTER_URL }} + E2E_ADX_TENANT_ID: ${{ secrets.E2E_ADX_TENANT_ID }} + diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 520701c57..26bf3fef8 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -6,32 +6,50 @@ jobs: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version-file: .nvmrc - - name: Install yarn dependencies - run: yarn install - env: - NODE_OPTIONS: '--max_old_space_size=4096' - - - name: Build - run: go build -v ./... - - - name: Build Frontend - run: yarn build - env: - NODE_OPTIONS: '--max_old_space_size=4096' - - name: Install Playwright Browsers - run: yarn playwright install --with-deps - - name: Start Grafana - run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD:/var/lib/grafana/plugins" grafana/grafana - - name: Run Playwright tests - run: yarn playwright test - - # - uses: actions/upload-artifact@v3 - # if: always() - # with: - # name: playwright-report - # path: playwright-report/ - # retention-days: 30 + - uses: actions/checkout@v3 + + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc + + - name: Install yarn dependencies + run: yarn install + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Build + run: go build -v ./... + + - name: Build Frontend + run: yarn build + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Install Playwright Browsers + run: yarn playwright install --with-deps + + - name: Start Grafana + run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD/dist:/var/lib/grafana/plugins/azure-data-explorer-datasource" grafana/grafana; sleep 30 + + - name: Run Playwright tests + run: yarn playwright test + env: + E2E_ADX_CLIENT_ID: ${{ secrets.E2E_ADX_CLIENT_ID }} + E2E_ADX_CLIENT_SECRET: ${{ secrets.E2E_ADX_CLIENT_SECRET }} + E2E_ADX_CLUSTER_URL: ${{ secrets.E2E_ADX_CLUSTER_URL }} + E2E_ADX_TENANT_ID: ${{ secrets.E2E_ADX_TENANT_ID }} + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: screenshot + path: screenshot/ + retention-days: 30 + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.github/workflows/pull-request-image.yml b/.github/workflows/pull-request-image.yml index 3bd270cb5..bed4b3111 100644 --- a/.github/workflows/pull-request-image.yml +++ b/.github/workflows/pull-request-image.yml @@ -105,6 +105,7 @@ jobs: with: issue-number: ${{ github.event.number }} body-includes: Use the following command to run this PR with Docker + - name: Update comment on PR if: steps.fc.outputs.comment-id != '' uses: peter-evans/create-or-update-comment@v3 @@ -118,6 +119,7 @@ jobs: ``` docker run --rm -p 3000:3000 grafana/plugin-builds:${{ github.event.pull_request.head.sha }}pre ``` + - name: Add comment to PR if: steps.fc.outputs.comment-id == '' uses: peter-evans/create-or-update-comment@v3 diff --git a/e2e/k6/k6.test.js b/e2e/k6/k6.spec.js similarity index 97% rename from e2e/k6/k6.test.js rename to e2e/k6/k6.spec.js index 73e809f24..4cbc3d604 100644 --- a/e2e/k6/k6.test.js +++ b/e2e/k6/k6.spec.js @@ -82,10 +82,10 @@ export async function addDatasource(page) { // form inputs const inputs = { - 'Client ID': '', - 'Client Secret': '', - 'Cluster URL': '', - 'Tenant ID': '', + 'Client ID': __ENV.E2E_ADX_CLIENT_ID, + 'Client Secret': __ENV.E2E_ADX_CLIENT_SECRET, + 'Cluster URL': __ENV.E2E_ADX_CLUSTER_URL, + 'Tenant ID': __ENV.E2E_ADX_TENANT_ID, }; // fill in form inputs diff --git a/e2e/playwright/playwright.spec.ts b/e2e/playwright/playwright.spec.ts index 511c66ccf..04a368d9d 100644 --- a/e2e/playwright/playwright.spec.ts +++ b/e2e/playwright/playwright.spec.ts @@ -1,11 +1,11 @@ -import { test, expect } from '@playwright/test'; +import { test, expect, Page } from '@playwright/test'; import { selectors } from '@grafana/e2e-selectors'; import { v4 as uuidv4 } from 'uuid'; const DASHBOARD_TITLE = `e2e-test-dashboard-${uuidv4()}`; const DATASOURCE_NAME = `adx-e2e-test-${uuidv4()}`; -const getDashboardUid = (url) => { +const getDashboardUid = (url: string) => { const matches = new URL(url).pathname.match(/\/d\/([^/]+)/); if (matches && Array.isArray(matches) && matches.length > 0) { @@ -15,7 +15,7 @@ const getDashboardUid = (url) => { } }; -test('Login', async ({ page }) => { +async function login(page: Page) { await page.goto(`http://localhost:3000${selectors.pages.Login.url}`, { waitUntil: 'networkidle', }); @@ -31,17 +31,17 @@ test('Login', async ({ page }) => { }; // login - fields.username.fill('admin'); - fields.password.fill('admin'); + await fields.username.fill('admin'); + await fields.password.fill('admin'); await buttons.submit.click(); // checks page for skip change password screen - expect(buttons.skip).toBeAttached(); + await expect(buttons.skip.isVisible()).toBeTruthy(); await buttons.skip.click(); -}); +} -test('Add datasource', async ({ page }) => { +async function addDatasource(page: Page) { await page.goto(`http://localhost:3000${selectors.pages.AddDataSource.url}`, { waitUntil: 'networkidle', }); @@ -53,29 +53,26 @@ test('Add datasource', async ({ page }) => { // name datasource const dsName = page.locator(`input[aria-label="${selectors.pages.DataSource.name}"]`); - dsName.fill(''); - dsName.fill(`${DATASOURCE_NAME}`); - - // form inputs - const inputs = { - 'Client ID': '', - 'Client Secret': '', - 'Cluster URL': '', - 'Tenant ID': '', - }; + await dsName.fill(''); + await dsName.fill(`${DATASOURCE_NAME}`); + + await page.screenshot({ path: 'screenshot/screenshot.png', fullPage: true }); // fill in form inputs - Object.entries(inputs).forEach(([key, value]) => page.locator(`input[aria-label="${key}"]`).fill(value)); + await page.locator(`input[aria-label="Tenant ID"]`).fill(process.env.E2E_ADX_TENANT_ID!); + await page.locator(`input[aria-label="Client ID"]`).fill(process.env.E2E_ADX_CLIENT_ID!); + await page.locator(`input[aria-label="Client Secret"]`).fill(process.env.E2E_ADX_CLIENT_SECRET!); + await page.locator(`input[aria-label="Cluster URL"]`).fill(process.env.E2E_ADX_CLUSTER_URL!); // save and test const saveBtn = page.locator(`button[data-testid="data-testid ${selectors.pages.DataSource.saveAndTest}"]`); await saveBtn.click(); // checks the page for the data source is working message - expect(page.locator('[aria-label="Create a dashboard"]')).toContainText('building a dashboard'); -}); + await expect(page.locator('[aria-label="Create a dashboard"]')).toContainText('building a dashboard'); +} -test('Add dashboard', async ({ page }) => { +async function addDashboard(page: Page) { await page.goto(`http://localhost:3000${selectors.pages.AddDashboard.url}`, { waitUntil: 'networkidle' }); // checks for the create dashboard button @@ -88,18 +85,18 @@ test('Add dashboard', async ({ page }) => { // name dashboard const dashboardTitleInput = page.locator(`input[aria-label="${selectors.pages.SaveDashboardAsModal.newName}"]`); - dashboardTitleInput.fill(''); - dashboardTitleInput.fill(DASHBOARD_TITLE); + await dashboardTitleInput.fill(''); + await dashboardTitleInput.fill(DASHBOARD_TITLE); // save dashboard const saveDashboardModalButton = page.locator(`button[aria-label="${selectors.pages.SaveDashboardAsModal.save}"]`); await saveDashboardModalButton.click(); // checks that the dashboard is created successfully - expect(page.locator('div[data-testid="data-testid Alert success"]')).toBeAttached(); -}); + await expect(page.locator('div[data-testid="data-testid Alert success"]').isVisible()).toBeTruthy(); +} -test('Configure panel', async ({ page }) => { +async function configurePanel(page: Page) { const dashboardURL = page.url(); await page.goto(`${dashboardURL}`, { waitUntil: 'networkidle' }); @@ -108,33 +105,43 @@ test('Configure panel', async ({ page }) => { await addPanelButton.click(); // select data source for panel - page.locator('input[placeholder="Search data source"]').fill(`${DATASOURCE_NAME}`); - page.keyboard.down('Tab'); - page.keyboard.down('Enter'); + await page.locator('input[placeholder="Search data source"]').fill(`${DATASOURCE_NAME}`); + await page.keyboard.down('Tab'); + await page.keyboard.down('Enter'); // select database const database = page.locator(`[aria-label="Database"]`); await database.click(); - database.fill('PerfTest'); - page.keyboard.down('Enter'); + await database.fill('PerfTest'); + await page.keyboard.down('Enter'); // select table const table = page.locator(`[aria-label="Table"]`); await table.click(); - table.fill('PerfTest'); - page.keyboard.down('Enter'); + await table.fill('PerfTest'); + await page.keyboard.down('Enter'); // run query - const runQueryBtn = page.locator(`[data-testid="data-testid run-query"]`); - await runQueryBtn.click(); + // const runQueryBtn = page.locator(`[data-testid="data-testid run-query"]`); + // await runQueryBtn.click(); + // are there results? - const columns = page.locator(`[aria-label="Columns"]`); - await columns.click(); + // const columns = page.locator(`[aria-label="Columns"]`); + // await columns.click(); - expect(page.locator('[aria-label="Select options menu"]').innerHTML()).toContain('_val1_'); -}); + const html = await page.locator('[aria-label="Select options menu"]').innerHTML(); + await expect(html).toContain('_val1_'); + + // save panel + const savePanelBtn = page.locator(`button[title="Apply changes and save dashboard"]`); + await savePanelBtn.click(); + const saveDashButton = page.locator('button[aria-label="Save dashboard button"]'); + await saveDashButton.click(); + + await page.pause(); +} -test('Remove dashboard', async ({ page }) => { +export async function removeDashboard(page: Page) { const dashboardUID = getDashboardUid(page.url()); await page.goto(`http://localhost:3000/d/${dashboardUID}`, { waitUntil: 'networkidle' }); @@ -157,5 +164,13 @@ test('Remove dashboard', async ({ page }) => { await deleteDashboardModalButton.click(); // checks for success alert message - expect(page.locator('div[data-testid="data-testid Alert success"]')).toBeAttached(); + await expect(page.locator('div[data-testid="data-testid Alert success"]').isVisible()).toBeTruthy(); +} + +test('Azure Data Explorer dashboard', async ({ page }) => { + await login(page); + await addDatasource(page); + await addDashboard(page); + await configurePanel(page); + await removeDashboard(page); }); diff --git a/package.json b/package.json index cf97d8726..59ae81274 100644 --- a/package.json +++ b/package.json @@ -99,9 +99,5 @@ "resolutions": { "**/@testing-library/dom": "7.31.2" }, - "packageManager": "yarn@1.22.19", - "volta": { - "node": "18.18.0", - "yarn": "1.22.19" - } + "packageManager": "yarn@1.22.19" }