From e8de8a7153ac6ccd3b41f20f89c964f9b3463add Mon Sep 17 00:00:00 2001 From: Sarah Zinger Date: Fri, 29 Mar 2024 11:42:14 -0400 Subject: [PATCH 1/2] Add e2e tests for config editor --- .github/workflows/e2e.yml | 15 ++++--- CONTRIBUTING.md | 41 ++++++++++++++++++ package.json | 4 +- tests/configEditor.spec.ts | 87 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 tests/configEditor.spec.ts diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index dbc912ed..c373caab 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -59,6 +59,7 @@ jobs: run: | docker-compose pull GRAFANA_VERSION=${{ matrix.GRAFANA_IMAGE.VERSION }} GRAFANA_IMAGE=${{ matrix.GRAFANA_IMAGE.NAME }} docker-compose up -d + - name: Wait for Grafana to start uses: nev7n/wait_for_response@v1 with: @@ -67,12 +68,14 @@ jobs: timeout: 60000 interval: 500 + - name: Get secrets for e2e tests and set in env + id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main + with: + repo_secrets: | + AWS_ACCESS_KEY=e2e:AWS_ACCESS_KEY + AWS_SECRET_KEY=e2e:AWS_SECRET_KEY + - name: Run Playwright tests id: run-tests run: yarn playwright test - - - name: Publish report to GCS - if: ${{ github.repository_owner == 'grafana' && (always() && steps.run-tests.outcome == 'success') || (failure() && steps.run-tests.outcome == 'failure') }} - uses: grafana/plugin-actions/publish-report@main - with: - grafana-version: ${{ matrix.GRAFANA_IMAGE.VERSION }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2627a749..f6325066 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,3 +114,44 @@ You need to have commit rights to the GitHub repository to publish a release. 2. Update the `CHANGELOG.md` by copy and pasting the relevant PRs from [Github's Release drafter interface](https://github.com/grafana/iot-sitewise-datasource/releases/new) or by running `yarn generate-release-notes` (you'll need to install the [gh cli](https://cli.github.com/) and [jq](https://jqlang.github.io/jq/) to run this command). 3. PR the changes. 4. Once merged, follow the Drone release process that you can find [here](https://github.com/grafana/integrations-team/wiki/Plugin-Release-Process#drone-release-process) + +## E2E Tests + +This plugin uses [playwright](https://playwright.dev/) and [@grafana/plugin-e2e](https://github.com/grafana/plugin-tools/tree/main/packages/plugin-e2e) for e2e end tests. + +To get the best fidelity, we make live requests to AWS for many of our e2e tests. In order to run them you will need to create an AWS User and secret/access keys and add them in either as env variables (`AWS_ACCESS_KEY` and `AWS_SECRET_KEY`) which is how we run our tests in CI or add a yaml file to the provisioning repo like so: + +``` +apiVersion: 1 + +deleteDatasources: + - name: sitewise + orgId: 1 + +datasources: + - name: sitewise + type: grafana-iot-sitewise-datasource + editable: true + jsonData: + authType: keys + defaultRegion: us-east-1 + secureJsonData: + accessKey: {your access key here} + secretKey: {your secret key here} +``` + +### Running e2e tests locally + +To run e2e tests locally: + +``` +yarn run e2e +``` + +This will then print out a report that can be viewed. Or To run e2e tests locally with [UI mode](https://playwright.dev/docs/test-ui-mode) for easier debugging: + +``` +yarn run e2e:debug +``` + +You may also wish to enable "traces" in the playwright.config.ts file which will show screenshots of failures and network requests. diff --git a/package.json b/package.json index 6b283731..f90c29cd 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,6 @@ "scripts": { "build": "webpack -c ./.config/webpack/webpack.config.ts --env production", "dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development", - "e2e": "yarn exec cypress install && yarn exec grafana-e2e run", - "e2e:update": "yarn exec cypress install && yarn exec grafana-e2e run --update-screenshots", "generate-release-notes": "PREV_TAG=$(git tag | tail -n 1) && gh api --method POST /repos/grafana/iot-sitewise-datasource/releases/generate-notes -f tag_name=v${npm_package_version} -f target_commitish=main -f previous_tag_name=${PREV_TAG} | jq -r .body", "lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx .", "lint:fix": "yarn run lint --fix", @@ -18,6 +16,8 @@ "typecheck": "tsc --noEmit", "test:coverage": "jest --coverage", "test:coverage:changes": "jest --coverage --changedSince=origin/main", + "e2e:debug": "npx playwright test --ui", + "e2e": "npx playwright test", "watch": "webpack -w -c ./.config/webpack/webpack.config.ts --env development" }, "repository": "github:grafana/iot-sitewise-datasource", diff --git a/tests/configEditor.spec.ts b/tests/configEditor.spec.ts new file mode 100644 index 00000000..e24eb30c --- /dev/null +++ b/tests/configEditor.spec.ts @@ -0,0 +1,87 @@ +import { test, expect, ReadProvisionedDataSourceArgs, DataSourceSettings } from '@grafana/plugin-e2e'; +import { SitewiseOptions, SitewiseSecureJsonData } from '../src/types'; + +test.describe('ConfigEditor', () => { + test('invalid credentials should return a 400 status code', async ({ createDataSourceConfigPage, page }) => { + // create a new datasource and navigate to config page + const configPage = await createDataSourceConfigPage({ type: 'grafana-iot-sitewise-datasource' }); + + // fill in the config form + await page.getByLabel(/^Authentication Provider/).fill('Access & secret key'); + await page.keyboard.press('Enter'); + await page.getByLabel('Access Key ID').fill('bad1credentials'); + await page.getByLabel('Secret Access Key').fill('very-bad-credentials'); + await page.getByLabel('Default Region').fill('us-east-1'); + await page.keyboard.press('Enter'); + + // click save and test + const response = await configPage.saveAndTest(); + + // expect network response have error + const body = await response.json(); + expect(body).toHaveProperty('status', 'ERROR'); + expect(body.message).toContain('invalid'); + + // expect error to be shown in the UI + const errorMessage = page.getByText('The security token included in the request is invalid'); + expect(errorMessage).toBeVisible(); + }); + + test('valid credentials should return a 200 status code', async ({ + createDataSourceConfigPage, + readProvisionedDataSource, + page, + }) => { + const { accessKey, secretKey } = await getTestCredentials(readProvisionedDataSource); + + // create a new datasource and navigate to config page + const configPage = await createDataSourceConfigPage({ type: 'grafana-iot-sitewise-datasource' }); + + // fill in the config form + await page.getByLabel(/^Authentication Provider/).fill('Access & secret key'); + await page.keyboard.press('Enter'); + await page.getByLabel('Access Key ID').fill(accessKey); + await page.getByLabel('Secret Access Key').fill(secretKey); + await page.getByLabel('Default Region').fill('us-east-1'); + await page.keyboard.press('Enter'); + + // click save and test + const response = await configPage.saveAndTest(); + + // expect network response have success message + const body = await response.json(); + expect(body).toHaveProperty('status', 'OK'); + + // expect success message to be shown in the UI + const successMessage = page.getByText('OK'); + expect(successMessage).toBeVisible(); + }); +}); + +async function getTestCredentials( + readProvisionedDataSource: (args: ReadProvisionedDataSourceArgs) => Promise> +) { + // get access key from env (in ci) or from provisioning repo (if running e2e test locally) + let accessKey = ''; + let secretKey = ''; + if (process.env.AWS_ACCESS_KEY && process.env.AWS_SECRET_KEY) { + accessKey = process.env.AWS_ACCESS_KEY; + secretKey = process.env.AWS_SECRET_KEY; + } else { + try { + const ds = await readProvisionedDataSource({ + fileName: 'iot-sitewise.yaml', + }); + if (!ds.secureJsonData || !ds.secureJsonData.accessKey || !ds.secureJsonData.secretKey) { + throw new Error('Provisioned datasource does not have valid credentials'); + } + accessKey = ds.secureJsonData.accessKey; + secretKey = ds.secureJsonData.secretKey; + } catch (err) { + throw new Error( + 'Missing valid credentials for e2e tests. Please provide AWS_ACCESS_KEY and AWS_SECRET_KEY in the environment variables or provision a datasource with valid credentials in the provisioning repo.' + ); + } + } + return { accessKey, secretKey }; +} From ab287351218ce42312095b56ffe3bb6fb24c6f8a Mon Sep 17 00:00:00 2001 From: Sarah Zinger Date: Fri, 29 Mar 2024 11:48:34 -0400 Subject: [PATCH 2/2] remove lingering references to cypress and update yml --- .github/workflows/e2e.yml | 4 ++-- .gitignore | 3 --- cspell.config.json | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c373caab..a016b2e8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -76,6 +76,6 @@ jobs: AWS_ACCESS_KEY=e2e:AWS_ACCESS_KEY AWS_SECRET_KEY=e2e:AWS_SECRET_KEY - - name: Run Playwright tests + - name: Run E2E tests id: run-tests - run: yarn playwright test + run: yarn run e2e diff --git a/.gitignore b/.gitignore index 4b106d7a..9805553d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ node_modules/ coverage/ ci/ -cypress/report.json -cypress/screenshots/actual -cypress/videos/ dist/ .idea/ .DS_Store diff --git a/cspell.config.json b/cspell.config.json index 708d2cf9..d78c4dc9 100644 --- a/cspell.config.json +++ b/cspell.config.json @@ -2,7 +2,6 @@ "language": "en", "ignorePaths": [ "coverage/**", - "cypress/**", "dist/**", "go.sum", "mage_output_file.go",