From 4c59fe8c4c4f1fd30efa349bd640d75f52a6e59e Mon Sep 17 00:00:00 2001 From: Pooria Mehregan Date: Tue, 14 May 2024 16:00:56 +0200 Subject: [PATCH] test(data-hunter): add e2e --- .gitignore | 4 + apps/forms-e2e/.env.test | 8 + apps/forms-e2e/.eslintrc.json | 4 +- apps/forms-e2e/playwright.config.ts | 5 +- apps/forms-e2e/project.json | 5 +- .../src/data-hunter/data/inputData.json | 9 + .../src/data-hunter/fixtures/basePage.ts | 14 + .../data-hunter/page-object-model/formPage.ts | 64 + .../src/data-hunter/tests/formPage.spec.ts | 17 + .../src/data-hunter/utils/helpers.ts | 13 + apps/forms-e2e/src/example.spec.ts | 8 - apps/forms-e2e/tsconfig.json | 3 +- .../data-hunter-form.module.css | 1 + .../header/components/menu-language/index.tsx | 2 +- .../components/menu-navigation/index.tsx | 2 +- libs/ui/src/lib/layout-root/index.tsx | 2 +- package.json | 5 +- yarn.lock | 1535 ++++++++--------- 18 files changed, 915 insertions(+), 786 deletions(-) create mode 100644 apps/forms-e2e/.env.test create mode 100644 apps/forms-e2e/src/data-hunter/data/inputData.json create mode 100644 apps/forms-e2e/src/data-hunter/fixtures/basePage.ts create mode 100644 apps/forms-e2e/src/data-hunter/page-object-model/formPage.ts create mode 100644 apps/forms-e2e/src/data-hunter/tests/formPage.spec.ts create mode 100644 apps/forms-e2e/src/data-hunter/utils/helpers.ts delete mode 100644 apps/forms-e2e/src/example.spec.ts diff --git a/.gitignore b/.gitignore index 9f77fde5..c7a89a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,9 +44,13 @@ out .env* /**/*/.env* !**/.env*.example +!**/*-e2e/.env.test # yarn .yarn # lint .eslintcache + +# test +playwright-report diff --git a/apps/forms-e2e/.env.test b/apps/forms-e2e/.env.test new file mode 100644 index 00000000..65522026 --- /dev/null +++ b/apps/forms-e2e/.env.test @@ -0,0 +1,8 @@ +# These are the environment variables used in the test environment + +DATAJEGER_EMAIL_ADDRESS=datajegeren@test.no +FDK_MAIL_SERVICE_ENDPOINT=/api/sendmail +FDK_MAIL_SERVICE_API_KEY=testapikey +FDK_BASE_URI=https://staging.fellesdatakatalog.digdir.no +FDK_COMMUNITY_BASE_URI=https://community.staging.fellesdatakatalog.digdir.no +FDK_REGISTRATION_BASE_URI=https://registrering.staging.fellesdatakatalog.digdir.no diff --git a/apps/forms-e2e/.eslintrc.json b/apps/forms-e2e/.eslintrc.json index cdbd057c..b8b20398 100644 --- a/apps/forms-e2e/.eslintrc.json +++ b/apps/forms-e2e/.eslintrc.json @@ -16,7 +16,9 @@ }, { "files": ["src/**/*.{ts,js,tsx,jsx}"], - "rules": {} + "rules": { + "playwright/expect-expect": "off" + } } ] } diff --git a/apps/forms-e2e/playwright.config.ts b/apps/forms-e2e/playwright.config.ts index 325bd97e..90781803 100644 --- a/apps/forms-e2e/playwright.config.ts +++ b/apps/forms-e2e/playwright.config.ts @@ -2,6 +2,8 @@ import { defineConfig, devices } from '@playwright/test'; import { nxE2EPreset } from '@nx/playwright/preset'; import { workspaceRoot } from '@nx/devkit'; +import path = require('path'); +import * as dotenv from 'dotenv'; // For CI, you may want to set BASE_URL to the deployed application. const baseURL = process.env['BASE_URI'] || 'http://127.0.0.1:3000'; @@ -10,13 +12,14 @@ const baseURL = process.env['BASE_URI'] || 'http://127.0.0.1:3000'; * Read environment variables from file. * https://github.com/motdotla/dotenv */ -// require('dotenv').config(); +dotenv.config({ path: path.resolve(__dirname, '.env.test') }); /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ ...nxE2EPreset(__filename, { testDir: './src' }), + reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { baseURL, diff --git a/apps/forms-e2e/project.json b/apps/forms-e2e/project.json index 48fe7141..46610472 100644 --- a/apps/forms-e2e/project.json +++ b/apps/forms-e2e/project.json @@ -2,7 +2,8 @@ "name": "forms-e2e", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/forms-e2e/src", - "implicitDependencies": ["forms"], "// targets": "to see all targets run: nx show project forms-e2e --web", - "targets": {} + "targets": { + + } } diff --git a/apps/forms-e2e/src/data-hunter/data/inputData.json b/apps/forms-e2e/src/data-hunter/data/inputData.json new file mode 100644 index 00000000..119dd708 --- /dev/null +++ b/apps/forms-e2e/src/data-hunter/data/inputData.json @@ -0,0 +1,9 @@ +{ + "dataset": "John Wick's dataset", + "location": "Stockholm", + "efforts": "High", + "name": "John Wick", + "email": "johnwick@email.com", + "organizationNumber": "123456789", + "phoneNumber": "12345678" +} diff --git a/apps/forms-e2e/src/data-hunter/fixtures/basePage.ts b/apps/forms-e2e/src/data-hunter/fixtures/basePage.ts new file mode 100644 index 00000000..421ecae3 --- /dev/null +++ b/apps/forms-e2e/src/data-hunter/fixtures/basePage.ts @@ -0,0 +1,14 @@ +import { test as base } from '@playwright/test'; +import FormPage from '../page-object-model/formPage'; +import { generateAccessibilityBuilder } from '../utils/helpers'; + +export const test = base.extend({ + dataHunterFormPage: async ({ page }, use) => { + const accessibilityBuilder = await generateAccessibilityBuilder(page); + const dataHunterFormPage = new FormPage(page, accessibilityBuilder); + await dataHunterFormPage.goto(); + await use(dataHunterFormPage); + }, +}); + +export { expect } from '@playwright/test'; diff --git a/apps/forms-e2e/src/data-hunter/page-object-model/formPage.ts b/apps/forms-e2e/src/data-hunter/page-object-model/formPage.ts new file mode 100644 index 00000000..9ac11252 --- /dev/null +++ b/apps/forms-e2e/src/data-hunter/page-object-model/formPage.ts @@ -0,0 +1,64 @@ +import { Dictionary, getDictionary } from '@fdk-frontend/dictionaries'; +import { expect, Page } from '@playwright/test'; +import * as mockData from '../data/inputData.json'; +import type AxeBuilder from '@axe-core/playwright'; + +export default class FormPage { + dataHunterPageUrl = '/forms/en/data-hunter'; + page: Page; + dictionary: Dictionary; + accessibilityBuilder; + + constructor(page: Page, accessibilityBuilder?: AxeBuilder) { + this.page = page; + getDictionary('en').then((dict) => (this.dictionary = dict)); + this.accessibilityBuilder = accessibilityBuilder; + } + + public async goto() { + await this.page.goto(this.dataHunterPageUrl); + } + + public async checkAccessibility() { + if (!this.accessibilityBuilder) { + return; + } + const result = await this.accessibilityBuilder.analyze(); + expect.soft(result.violations).toEqual([]); + } + + // Locators + pageTitle = () => this.page.getByRole('heading', { name: this.dictionary.dataHunterForm.title }); + pageDescription = () => this.page.getByText(this.dictionary.dataHunterForm.description); + datasetInput = () => this.page.getByLabel(this.dictionary.dataHunterForm.dataset.label); + locationInput = () => this.page.getByLabel(this.dictionary.dataHunterForm.location.label); + attemptsInput = () => this.page.getByLabel(this.dictionary.dataHunterForm.efforts.label); + nameInput = () => this.page.getByLabel(this.dictionary.name); + emailInput = () => this.page.getByLabel(this.dictionary.email); + organizationNumberInput = () => this.page.getByLabel(this.dictionary.organizationNumber); + phoneNumberInput = () => this.page.getByLabel(this.dictionary.phoneNumber); + submitButton = () => this.page.getByRole('button', { name: this.dictionary.submitRequest }); + + // Actions + public async checkPageTitleText() { + await expect(this.pageTitle()).toHaveText(this.dictionary.dataHunterForm.title); + } + + public async checkPageDescriptionText() { + await expect(this.pageDescription()).toHaveText(this.dictionary.dataHunterForm.description); + } + + public async fillForm() { + await this.datasetInput().fill(mockData.dataset); + await this.locationInput().fill(mockData.location); + await this.attemptsInput().fill(mockData.efforts); + await this.nameInput().fill(mockData.name); + await this.emailInput().fill(mockData.email); + await this.organizationNumberInput().fill(mockData.organizationNumber); + await this.phoneNumberInput().fill(mockData.phoneNumber); + } + + public async submitForm() { + await this.submitButton().click(); + } +} diff --git a/apps/forms-e2e/src/data-hunter/tests/formPage.spec.ts b/apps/forms-e2e/src/data-hunter/tests/formPage.spec.ts new file mode 100644 index 00000000..c4cace16 --- /dev/null +++ b/apps/forms-e2e/src/data-hunter/tests/formPage.spec.ts @@ -0,0 +1,17 @@ +import { test } from '../fixtures/basePage'; + + + +test('should not have any automatically detectable accessibility issues', async ({ dataHunterFormPage }) => { + await dataHunterFormPage.checkAccessibility(); +}); + +test('check page text', async ({ dataHunterFormPage }) => { + await dataHunterFormPage.checkPageTitleText(); + await dataHunterFormPage.checkPageDescriptionText(); +}); + +test('fill form', async ({ dataHunterFormPage }) => { + await dataHunterFormPage.fillForm(); + await dataHunterFormPage.submitForm(); +}); diff --git a/apps/forms-e2e/src/data-hunter/utils/helpers.ts b/apps/forms-e2e/src/data-hunter/utils/helpers.ts new file mode 100644 index 00000000..287f1cdd --- /dev/null +++ b/apps/forms-e2e/src/data-hunter/utils/helpers.ts @@ -0,0 +1,13 @@ +import AxeBuilder from "@axe-core/playwright"; +import { Page } from "@playwright/test"; + +export const generateAccessibilityBuilder = async (page: Page) => + new AxeBuilder({ page }).withTags([ + 'wcag2a', + 'wcag2aa', + 'wcag2aaa', + 'wcag21a', + 'wcag21aa', + 'wcag22aa', + 'best-practice', + ]); diff --git a/apps/forms-e2e/src/example.spec.ts b/apps/forms-e2e/src/example.spec.ts deleted file mode 100644 index d86a5303..00000000 --- a/apps/forms-e2e/src/example.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { test, expect } from '@playwright/test'; - -test('has title', async ({ page }) => { - await page.goto('/forms/data-hunter'); - - // Expect h1 to contain a substring. - expect(await page.title()).toBe('Forms'); -}); diff --git a/apps/forms-e2e/tsconfig.json b/apps/forms-e2e/tsconfig.json index 114364a1..0ff79f25 100644 --- a/apps/forms-e2e/tsconfig.json +++ b/apps/forms-e2e/tsconfig.json @@ -4,7 +4,8 @@ "allowJs": true, "outDir": "../../dist/out-tsc", "module": "commonjs", - "sourceMap": false + "sourceMap": false, + "resolveJsonModule": true }, "include": [ "**/*.ts", diff --git a/apps/forms/app/[lang]/data-hunter/components/data-hunter-form/data-hunter-form.module.css b/apps/forms/app/[lang]/data-hunter/components/data-hunter-form/data-hunter-form.module.css index d8e55595..fc4e7665 100644 --- a/apps/forms/app/[lang]/data-hunter/components/data-hunter-form/data-hunter-form.module.css +++ b/apps/forms/app/[lang]/data-hunter/components/data-hunter-form/data-hunter-form.module.css @@ -16,6 +16,7 @@ .button { margin-top: 3rem; align-self: flex-start; + background-color: #0057A3; } .orgNumberField { diff --git a/libs/ui/src/lib/header/components/menu-language/index.tsx b/libs/ui/src/lib/header/components/menu-language/index.tsx index 0bd75522..b5a33ee4 100644 --- a/libs/ui/src/lib/header/components/menu-language/index.tsx +++ b/libs/ui/src/lib/header/components/menu-language/index.tsx @@ -27,7 +27,7 @@ const LanguageMenu = ({ triggerText, className }: Props) => { return ( - + {triggerText} diff --git a/libs/ui/src/lib/header/components/menu-navigation/index.tsx b/libs/ui/src/lib/header/components/menu-navigation/index.tsx index 383c9e82..be3e4129 100644 --- a/libs/ui/src/lib/header/components/menu-navigation/index.tsx +++ b/libs/ui/src/lib/header/components/menu-navigation/index.tsx @@ -22,7 +22,7 @@ const NavigationMenu = ({ triggerText, links }: NavigationMenuProps) => ( {triggerText} - + diff --git a/libs/ui/src/lib/layout-root/index.tsx b/libs/ui/src/lib/layout-root/index.tsx index 98db02dc..9ca0b92f 100644 --- a/libs/ui/src/lib/layout-root/index.tsx +++ b/libs/ui/src/lib/layout-root/index.tsx @@ -22,7 +22,7 @@ const RootLayout = async ({ children, params }: RootLayoutProps) => {
- {children} +
{children}