Skip to content

Commit

Permalink
Merge pull request #72 from Informasjonsforvaltning/develop
Browse files Browse the repository at this point in the history
test(data-hunter): add e2e
  • Loading branch information
pooriamehregan authored Jun 6, 2024
2 parents ee1a1ba + 27a0be1 commit e14e51c
Show file tree
Hide file tree
Showing 95 changed files with 10,335 additions and 2,147 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,14 @@ out
.env*
/**/*/.env*
!**/.env*.example
!**/*-e2e/.env.test

# yarn
.yarn

# lint
.eslintcache

# test
playwright-report
storybook-static
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
/coverage
/.nx
/node_modules

/.nx/cache
4 changes: 3 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"plugins": ["prettier-plugin-sort-json"],
"printWidth": 120,
"useTabs": false,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"singleAttributePerLine": true
"singleAttributePerLine": true,
"jsonRecursiveSort": true
}
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"ms-playwright.playwright",
"github.copilot",
"nrwl.angular-console",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"firsttris.vscode-jest-runner"
]
}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ comes with a LSP for Vim users.
## Editing text files

You can find the text files used in the project in the `libs/dictionaries/src/lib/dictionaries` folder.

## Notes

`mail-sender-service` in `forms/data-hunter` cannot be tested in staging and demo. It is only available in production.
1 change: 1 addition & 0 deletions __mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub';
8 changes: 8 additions & 0 deletions apps/forms-e2e/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# These are the environment variables used in the test environment

DATAJEGER_EMAIL_ADDRESS=[email protected]
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
4 changes: 3 additions & 1 deletion apps/forms-e2e/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
},
{
"files": ["src/**/*.{ts,js,tsx,jsx}"],
"rules": {}
"rules": {
"playwright/expect-expect": "off"
}
}
]
}
5 changes: 4 additions & 1 deletion apps/forms-e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand Down
5 changes: 2 additions & 3 deletions apps/forms-e2e/project.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"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",
"name": "forms-e2e",
"sourceRoot": "apps/forms-e2e/src",
"targets": {}
}
9 changes: 9 additions & 0 deletions apps/forms-e2e/src/data-hunter/data/inputData.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"dataset": "John Wick's dataset",
"efforts": "High",
"email": "[email protected]",
"location": "Stockholm",
"name": "John Wick",
"organizationNumber": "123456789",
"phoneNumber": "12345678"
}
14 changes: 14 additions & 0 deletions apps/forms-e2e/src/data-hunter/fixtures/basePage.ts
Original file line number Diff line number Diff line change
@@ -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, context }, use) => {
const accessibilityBuilder = await generateAccessibilityBuilder(page);
const dataHunterFormPage = new FormPage(page, context, accessibilityBuilder);
await dataHunterFormPage.goto();
await use(dataHunterFormPage);
},
});

export { expect } from '@playwright/test';
105 changes: 105 additions & 0 deletions apps/forms-e2e/src/data-hunter/page-object-model/formPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Dictionary, getDictionary } from '@fdk-frontend/dictionaries';
import { expect, Page, BrowserContext } 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;
context: BrowserContext;
dictionary: Dictionary;
accessibilityBuilder;
formData = {};

constructor(page: Page, context: BrowserContext, accessibilityBuilder?: AxeBuilder) {
getDictionary('en').then((dict) => (this.dictionary = dict));
this.page = page;
this.context = context;
this.accessibilityBuilder = accessibilityBuilder;
this.init();
}

async init() {
getDictionary('en').then((dict) => (this.dictionary = dict));
await this.addSubmitListener();
}

// 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 });
form = () => this.page.locator('[id="data-hunter-form"]');

// Helpers
public async goto(url: string = this.dataHunterPageUrl) {
await this.page.goto(url);
}

public async checkAccessibility() {
if (!this.accessibilityBuilder) {
return;
}
const result = await this.accessibilityBuilder.analyze();
expect.soft(result.violations).toEqual([]);
}

private async addSubmitListener() {
await this.form().evaluate((node) =>
node.addEventListener('submit', async (event) => {
event.preventDefault();
// eslint-disable-next-line no-undef
const formData = Array.from(new FormData(event.target as HTMLFormElement).entries()).reduce(
(data, [key, value]) => (!key.startsWith('$') ? { ...data, [key]: value } : data),
{},
);
node.setAttribute('submitted-form-data', JSON.stringify(formData));
}),
);
}

/**
* Validate form values after form submission, by checking the result of the new FormData()
*/
private async validateFormSubmission() {
const formData = await this.form().getAttribute('submitted-form-data');
if (!formData) {
throw new Error('Form submission failed');
}
this.formData = JSON.parse(formData);

for await (const [key, value] of Object.entries(this.formData)) {
expect(mockData[key as keyof typeof mockData]).toStrictEqual(value);
}
}

// 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();
await this.validateFormSubmission();
}
}
15 changes: 15 additions & 0 deletions apps/forms-e2e/src/data-hunter/tests/formPage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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 and submit form', async ({ dataHunterFormPage }) => {
await dataHunterFormPage.fillForm();
await dataHunterFormPage.submitForm();
});
12 changes: 12 additions & 0 deletions apps/forms-e2e/src/data-hunter/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import AxeBuilder from '@axe-core/playwright';
import { Page } from '@playwright/test';

export const generateAccessibilityBuilder = async (page: Page) =>
new AxeBuilder({ page }).withTags([
'wcag2a',
'wcag2aa',
'wcag21a',
'wcag21aa',
'wcag22aa',
'best-practice',
]);
8 changes: 0 additions & 8 deletions apps/forms-e2e/src/example.spec.ts

This file was deleted.

5 changes: 3 additions & 2 deletions apps/forms-e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"outDir": "../../dist/out-tsc",
"resolveJsonModule": true,
"sourceMap": false
},
"extends": "../../tsconfig.base.json",
"include": [
"**/*.ts",
"**/*.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
.textArea {
margin-top: 2rem;
.form {
display:flex;
flex-direction:column;
gap:2rem;
}

.textField {
width: 100%;
margin-top: 2rem;
align-self: flex-start;
}

Expand All @@ -13,11 +14,6 @@
width: 50%;
}

.button {
margin-top: 3rem;
align-self: flex-start;
}

.orgNumberField {
composes: textFieldHalfWidth;
}
Expand All @@ -33,3 +29,7 @@
.orgNumberField * input[type='number'] {
-moz-appearance: textfield;
}

.submitButton {
align-self: flex-start;
}
Loading

0 comments on commit e14e51c

Please sign in to comment.