From 33ca3d667e42fb37e87b498f34bd3241d0a0eea2 Mon Sep 17 00:00:00 2001 From: Marijn Kampf Date: Thu, 11 Jul 2024 14:15:51 +0100 Subject: [PATCH] Migration/dpm 130 performance testing playwright (#6991) * Made Playwright work with SSO (#6984) * Basic E2E tests * Update documentation --------- Co-authored-by: Peter Hudec --- .github/workflows/playwright.yml | 27 +++++++ .gitignore | 7 ++ docs/Running tests.md | 15 ++++ package-lock.json | 121 ++++++++++++++++++++++++++++++- package.json | 2 + playwright.config.ts | 112 ++++++++++++++++++++++++++++ tests/e2e/auth.ts | 31 ++++++++ tests/e2e/companies.spec.ts | 68 +++++++++++++++++ tests/e2e/contacts.spec.ts | 33 +++++++++ tests/e2e/dashboard.spec.ts | 25 +++++++ tests/e2e/interactions.spec.ts | 32 ++++++++ tests/e2e/investments.spec.ts | 21 ++++++ tests/e2e/search.spec.ts | 19 +++++ tests/e2e/utils.ts | 18 +++++ 14 files changed, 528 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/playwright.yml create mode 100644 playwright.config.ts create mode 100644 tests/e2e/auth.ts create mode 100644 tests/e2e/companies.spec.ts create mode 100644 tests/e2e/contacts.spec.ts create mode 100644 tests/e2e/dashboard.spec.ts create mode 100644 tests/e2e/interactions.spec.ts create mode 100644 tests/e2e/investments.spec.ts create mode 100644 tests/e2e/search.spec.ts create mode 100644 tests/e2e/utils.ts diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000000..467190be663 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 4039c2624b9..77adceed5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,10 @@ yalc.lock # Ignore gh pages for Storybook storybook-static/ + +playwright/.auth +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +.auth/ diff --git a/docs/Running tests.md b/docs/Running tests.md index d9f98734952..53ce110d227 100644 --- a/docs/Running tests.md +++ b/docs/Running tests.md @@ -196,6 +196,21 @@ or `$ npm run test:e2e:dit -- --spec test/end-to-end/cypress/specs/DIT/local-nav-spec.js` +# Performance E2E tests +The performance E2E tests use Playwright. Any current tests should only run non-mutating, non-destructive tests. + +In `playwright.config.ts` you can define which environment to run it against by settings the `baseURL`. + +To run against your local environment spin it assumes it is running already (`npm run develop`). + +If this is the first time running playwright you may need to run `npm install` to ensure you've got everything you need. + +Run tests headless: +`npx playwright test` + +Run tests in Playwright Test UI: +`npx playwright test --ui` + ## Accessibility tests The aim of this suite is to ensure our HTML pages are usable by as many people as possible. diff --git a/package-lock.json b/package-lock.json index 53cc567b877..4f0658937a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -108,12 +108,14 @@ "@chromatic-com/storybook": "^1.6.1", "@cypress/code-coverage": "^3.12.41", "@faker-js/faker": "^8.3.1", + "@playwright/test": "^1.45.1", "@storybook/addon-a11y": "^8.1.11", "@storybook/addon-essentials": "^8.1.11", "@storybook/addon-webpack5-compiler-babel": "^3.0.3", "@storybook/manager-api": "^8.1.11", "@storybook/react": "^8.1.11", "@storybook/react-webpack5": "^8.1.11", + "@types/node": "^20.14.10", "babel-loader": "^9.1.3", "babel-plugin-istanbul": "7.0.0", "chai": "^4.4.1", @@ -5749,6 +5751,21 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@playwright/test": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.1.tgz", + "integrity": "sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==", + "dev": true, + "dependencies": { + "playwright": "1.45.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@prisma/instrumentation": { "version": "5.16.1", "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-5.16.1.tgz", @@ -6901,6 +6918,15 @@ } } }, + "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@storybook/builder-webpack5/node_modules/css-loader": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", @@ -7607,6 +7633,15 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/@storybook/core-server/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@storybook/core-server/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7840,6 +7875,15 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/@storybook/core-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@storybook/csf": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.11.tgz", @@ -8015,6 +8059,15 @@ } } }, + "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@storybook/preview": { "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-8.1.11.tgz", @@ -8160,6 +8213,24 @@ } } }, + "node_modules/@storybook/react-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@storybook/router": { "version": "8.1.11", "resolved": "https://registry.npmjs.org/@storybook/router/-/router-8.1.11.tgz", @@ -8806,9 +8877,9 @@ } }, "node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", "dependencies": { "undici-types": "~5.26.4" } @@ -23406,6 +23477,50 @@ "pathe": "^1.1.2" } }, + "node_modules/playwright": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.1.tgz", + "integrity": "sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==", + "dev": true, + "dependencies": { + "playwright-core": "1.45.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.1.tgz", + "integrity": "sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", diff --git a/package.json b/package.json index 27986aa293c..a70fb0c975e 100644 --- a/package.json +++ b/package.json @@ -164,12 +164,14 @@ "@chromatic-com/storybook": "^1.6.1", "@cypress/code-coverage": "^3.12.41", "@faker-js/faker": "^8.3.1", + "@playwright/test": "^1.45.1", "@storybook/addon-a11y": "^8.1.11", "@storybook/addon-essentials": "^8.1.11", "@storybook/addon-webpack5-compiler-babel": "^3.0.3", "@storybook/manager-api": "^8.1.11", "@storybook/react": "^8.1.11", "@storybook/react-webpack5": "^8.1.11", + "@types/node": "^20.14.10", "babel-loader": "^9.1.3", "babel-plugin-istanbul": "7.0.0", "chai": "^4.4.1", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000000..6fb429aca80 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,112 @@ +import { defineConfig, devices } from '@playwright/test'; +import { BASE_URLS } from './tests/e2e/utils'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + // globalSetup: './tests/e2e/auth.setup', + testDir: './tests/e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: BASE_URLS.LOCALHOST, + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + ignoreHTTPSErrors: true, + }, + + /* Configure projects for major browsers */ + projects: [ + /** + * This "project" contains only a single test which doesn't test anything, + * but opens a browser where we can manually go through the SSO OAuth flow, + * at the end of which, the test preserves the session (cookies) in the + * ./.auth/user.json file + */ + { + name: 'auth', + testMatch: 'auth.ts', + timeout: 1000 * 60 * 100, + }, + { + name: 'foo', + testMatch: '**/*.spec.ts', + use: { + ...devices['Desktop Chrome'], + storageState: './.auth/user.json', + }, + /** + * We make the "auth" project a dependency of this project. + * The Playwright UI allows turning projects on and off. + * When we run this project for the first time, + * it will run "auth" first so we can manually go through the OAuth flow. + * After the OAuth flow succeeds, the tests in this project will be run with + * the authenticated context. + * If we run the tests again, we will have to go through the OAuth flow again, + * but we can toggle the "auth" project off in the UI and we can only run + * tests in this project still with the authenticated context. + * Should our session expire, we can just toggle "auth" back on and + * go through the OAuth flow again. + * Or alternatively, we can manually add a record for the "datahub.sid" + * session cookie to the ./.auth/user.json file? + */ + dependencies: ['auth'], + }, + + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, + + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/tests/e2e/auth.ts b/tests/e2e/auth.ts new file mode 100644 index 00000000000..85192ce3390 --- /dev/null +++ b/tests/e2e/auth.ts @@ -0,0 +1,31 @@ +import { chromium, test } from "playwright/test" +import fs from 'node:fs' + +const authFile = './.auth/user.json' + +test('auth', async () => { + /** + * We are using the low-level browser API here, + * which allows us to interact with the page. + * The normal testing API prevents form sumbission and link navigation + */ + const browser = await chromium.launch({headless: false}) + const context = await browser.newContext() + const page = await context.newPage() + + // If authFile exists use details. If tests fail remove auth file and the script below will + // induce the SSO login screen and generate a new one. + if (!fs.existsSync(authFile)) { + // Induce the SSO screen + // We are expecting to be redirected to SSO + await page.goto('/') + // This is here to force playwright to stop at the SSO page, + // because in the next step we are gonna make it wait for the URL we are already on... + await page.getByLabel('Next step') + // ...now we wait to be redirected back from SSO + await page.waitForURL('/') + // Finally we preserve the authenticated page context, + // which we will reuse in subsequent tests + await page.context().storageState({ path: authFile }); + } +}) diff --git a/tests/e2e/companies.spec.ts b/tests/e2e/companies.spec.ts new file mode 100644 index 00000000000..c9c655b161c --- /dev/null +++ b/tests/e2e/companies.spec.ts @@ -0,0 +1,68 @@ +import { test, expect } from '@playwright/test'; +import { getCompanyId } from './utils'; + +test.describe('companies', () => { + test('list', async ({ browser, page }) => { + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/sector?level__lte=0')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/sector?level__gte=1')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/headquarter-type')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/uk-region')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/administrative-area?country=81756b9a-5d95-e211-a939-e4115bead28a')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/administrative-area?country=5daf72a6-5d95-e211-a939-e4115bead28a')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/country')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/reminder/summary')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/search/company')), + page.goto('/companies?archived[0]=false&sortby=modified_on:desc&page=1'), + ]) + + await expect(page).toHaveTitle(/Companies - DBT Data Hub/) + await expect(page.getByRole('heading', {name: 'Companies', level: 1})).toBeVisible() + await expect(page.getByRole('heading', {name: 'companies', level: 2})).toContainText('companies') + }); + + test('company overview', async ({ browser, page, baseURL }) => { + const companyId = getCompanyId(baseURL) + + const companyInfo = `/api-proxy/v4/company/${companyId}` + const companyList = `/api-proxy/v4/company-list?items__company_id=${companyId}` + const exportWin = `/api-proxy/v4/company/${companyId}/export-win` + const dnbCount = `/api-proxy/v4/dnb/${companyId}/related-companies/count?include_manually_linked_companies=true` + const interaction = `/api-proxy/v3/search/interaction` + + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes(companyInfo)), + page.waitForResponse(resp => resp.url().includes(companyList)), + page.waitForResponse(resp => resp.url().includes(exportWin)), + page.waitForResponse(resp => resp.url().includes(dnbCount)), + page.waitForResponse(resp => resp.url().includes(interaction)), + page.goto(`/companies/${companyId}/overview`) + ]) + + await expect(page.getByRole('caption')).toHaveCount(7) + }); + + + test('company contacts', async ({ browser, page, baseURL }) => { + const companyId = getCompanyId(baseURL) + + const companyInfo = `/api-proxy/v4/company/${companyId}` + const companyList = `/api-proxy/v4/company-list?items__company_id=${companyId}` + const dnbCount = `/api-proxy/v4/dnb/${companyId}/related-companies/count?include_manually_linked_companies=true` + const contact = `/api-proxy/v3/search/contact` + + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes(`/api-proxy/v4/reminder/summary`)), + page.waitForResponse(resp => resp.url().includes(companyInfo)), + page.waitForResponse(resp => resp.url().includes(dnbCount)), + page.waitForResponse(resp => resp.url().includes(companyList)), + page.waitForResponse(resp => resp.url().includes(contact)), + page.goto(`/companies/${companyId}/contacts`), + ]) + + await expect(page.getByRole('heading', {name: 'contacts', level: 2})).toContainText('contacts') + }); + +}); + + diff --git a/tests/e2e/contacts.spec.ts b/tests/e2e/contacts.spec.ts new file mode 100644 index 00000000000..e37e4aa4969 --- /dev/null +++ b/tests/e2e/contacts.spec.ts @@ -0,0 +1,33 @@ +import { test, expect } from '@playwright/test'; +import { getCompanyId } from './utils'; + +test.describe('contacts', () => { + test('list', async ({ browser, page }) => { + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/sector')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/country')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/uk-region')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/reminder/summary')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v3/search/contact')), + page.goto('/contacts?archived[0]=false&sortby=modified_on:desc&page=1'), + ]) + + await expect(page).toHaveTitle(/Contacts - DBT Data Hub/) + await expect(page.getByRole('heading', {name: 'Contacts', level: 1})).toBeVisible() + await expect(page.getByRole('heading', {name: 'contacts', level: 2})).toContainText('contacts') + }); + + test('create contact form [view only]', async ({ baseURL, page }) => { + const companyId = getCompanyId(baseURL) + + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/administrative-area')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/reminder/summary') ), + page.waitForResponse(resp => resp.url().includes(`api-proxy/v4/company/${companyId}`)), + page.goto(`/contacts/create?company=${companyId}`), + ]) + + await expect(page).toHaveTitle(/Contacts - DBT Data Hub/) + await expect(page.getByRole('heading', {name: 'Add contact', level: 1})).toContainText('Add contact') + }); +}); \ No newline at end of file diff --git a/tests/e2e/dashboard.spec.ts b/tests/e2e/dashboard.spec.ts new file mode 100644 index 00000000000..c51ca27407c --- /dev/null +++ b/tests/e2e/dashboard.spec.ts @@ -0,0 +1,25 @@ +import { test, expect } from '@playwright/test'; + +test('dashboard', async ({ browser, page }) => { + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/reminder/summary')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/search/task')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v3/search/investment_project')), + page.goto('/'), + ]) + + await expect(page).toHaveTitle(/Dashboard - DBT Data Hub/) + + // Only check for elements that appear regardless whether there are items as we don't know + // what the user has in their lists. + await page.getByRole('tab', { name: 'Tasks' }).click(); + await expect(page.locator('a[href="/tasks/create"]')).toHaveCount(1) + await page.getByRole('tab', { name: 'Company lists' }).click(); + await expect(page.getByRole('heading', {name: 'My companies lists'})).toBeVisible() + // Investment projects shows two completely different pages depending if there are any. + // await page.getByRole('tab', { name: 'Investment projects' }).click(); + await page.getByRole('tab', { name: 'Export projects' }).click(); + await expect(page.locator('a[href="/exportwins"]')).toHaveCount(1) + await page.getByRole('tab', { name: 'Referrals' }).click(); + await expect(page.getByRole('heading', {name: 'received referrals'})).toBeVisible() +}); diff --git a/tests/e2e/interactions.spec.ts b/tests/e2e/interactions.spec.ts new file mode 100644 index 00000000000..dd80c4aef66 --- /dev/null +++ b/tests/e2e/interactions.spec.ts @@ -0,0 +1,32 @@ +import { test, expect } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/service')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/sector')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/policy-area')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/policy-issue-type')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/one-list-tier')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/reminder/summary')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v3/search/interaction')), + page.goto('/interactions?sortby=date:desc&page=1'), + ]) + await expect(page).toHaveTitle(/Interactions - DBT Data Hub/) +}); + +test.describe('interactions', () => { + test('list', async ({ browser, page }) => { + await expect(page.getByRole('heading', {name: 'interactions', level: 2})).toContainText('interactions') + }); + + test('view an interaction', async ({ browser, page }) => { + // await page.locator('[data-test="primary-navigation"]').getByRole('link', { name: 'Interactions' }).click(); + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/interaction/') && resp.status() === 200), + // Click on the title of the first interaction in list. + await page.locator('li[data-test="collection-item"] h3 a').first().click(), + ]) + await expect(page).toHaveTitle(/- Interactions - DBT Data Hub/) + await expect(page.locator('li[aria-current="page"]')).toContainText('Interaction') + }); +}); \ No newline at end of file diff --git a/tests/e2e/investments.spec.ts b/tests/e2e/investments.spec.ts new file mode 100644 index 00000000000..969cc1c0c3f --- /dev/null +++ b/tests/e2e/investments.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from '@playwright/test'; + +test.describe('investments', () => { + test('investment projects list', async ({ browser, page }) => { + const [response] = await Promise.all([ + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/country')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/investment-type')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/likelihood-to-land')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/investment-project-stage')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/sector')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/metadata/uk-region')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v4/reminder/summary')), + page.waitForResponse(resp => resp.url().includes('/api-proxy/v3/search/investment_project')), + page.goto('/investments'), + ]) + + await expect(page).toHaveTitle(/Projects - Investments - DBT Data Hub/) + await expect(page.getByRole('heading', {name: 'Projects', level: 1})).toBeVisible() + await expect(page.getByRole('heading', {name: 'investment projects', level: 2})).toContainText('investment projects') + }); +}); diff --git a/tests/e2e/search.spec.ts b/tests/e2e/search.spec.ts new file mode 100644 index 00000000000..8107d5277fa --- /dev/null +++ b/tests/e2e/search.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from '@playwright/test'; + +test.describe('search', () => { + [ + { name: 'Companies', slug: 'companies' }, + { name: 'Contacts', slug: 'contacts' }, + { name: 'Events', slug: 'events' }, + { name: 'Interactions', slug: 'interactions' }, + { name: 'Investment projects', slug: 'investment-projects' }, + { name: 'Orders', slug: 'omis' }, + ].forEach(({ name, slug }) => { + test(`${name}`, async ({ page }) => { + await page.goto(`/search/${slug}?term=test`), + + await expect(page).toHaveTitle(`${name} - Search - DBT Data Hub`) + await expect(page.getByRole('heading', {name: 'results matching test'})).toBeVisible() + }); + }); +}); diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts new file mode 100644 index 00000000000..590fbe6abe5 --- /dev/null +++ b/tests/e2e/utils.ts @@ -0,0 +1,18 @@ +export const BASE_URLS = { + LOCALHOST: 'http://127.0.0.1:3000', + DEV: 'https://dev.datahub.uktrade.digital', + STAGING: 'https://staging.datahub.uktrade.digital', + UAT: 'https://uat.datahub.uktrade.digital', + TEMP_PROD: 'https://datahub.prod.uktrade.digital', + PROD: 'https://www.datahub.trade.gov.uk', +}; + +export function getCompanyId(baseURL:string):string { + // Returns an id of a company in the database + if (baseURL == BASE_URLS.TEMP_PROD || baseURL == BASE_URLS.PROD) { + // Company in DB with Company Tree + return 'eca13ac7-a098-e211-a939-e4115bead28a' + } + // One list corp + return '375094ac-f79a-43e5-9c88-059a7caa17f0' +}