From d007521842107c36d67e48382cf457d8e4ef3223 Mon Sep 17 00:00:00 2001 From: Cesare De Cal Date: Wed, 3 Jul 2024 22:37:21 +0200 Subject: [PATCH] implement e2e tests with PlayWright --- frontend/.gitignore | 4 ++ frontend/package-lock.json | 60 +++++++++++++++++++++++++++ frontend/package.json | 1 + frontend/playwright.config.ts | 78 +++++++++++++++++++++++++++++++++++ frontend/tests/home.spec.ts | 44 ++++++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100644 frontend/playwright.config.ts create mode 100644 frontend/tests/home.spec.ts diff --git a/frontend/.gitignore b/frontend/.gitignore index 0c43a1c..6f1cf2d 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -19,3 +19,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3433754..7c948df 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "@playwright/test": "^1.45.1", "@tanstack/eslint-plugin-query": "^5.49.0", "babel-plugin-module-resolver": "^5.0.2", "customize-cra": "^1.0.0", @@ -3605,6 +3606,21 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.45.1", + "resolved": "https://arm.seli.gic.ericsson.se/artifactory/api/npm/proj-bmas-ndo-npm-all/@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/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.15", "resolved": "https://arm.seli.gic.ericsson.se/artifactory/api/npm/proj-bmas-ndo-npm-all/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz", @@ -13017,6 +13033,50 @@ "node": ">=4" } }, + "node_modules/playwright": { + "version": "1.45.1", + "resolved": "https://arm.seli.gic.ericsson.se/artifactory/api/npm/proj-bmas-ndo-npm-all/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://arm.seli.gic.ericsson.se/artifactory/api/npm/proj-bmas-ndo-npm-all/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://arm.seli.gic.ericsson.se/artifactory/api/npm/proj-bmas-ndo-npm-all/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/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://arm.seli.gic.ericsson.se/artifactory/api/npm/proj-bmas-ndo-npm-all/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 65adbef..00cadfd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -52,6 +52,7 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "@playwright/test": "^1.45.1", "@tanstack/eslint-plugin-query": "^5.49.0", "babel-plugin-module-resolver": "^5.0.2", "customize-cra": "^1.0.0", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..7695af0 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,78 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * 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({ + testDir: './tests', + /* 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: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + 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/frontend/tests/home.spec.ts b/frontend/tests/home.spec.ts new file mode 100644 index 0000000..fd38169 --- /dev/null +++ b/frontend/tests/home.spec.ts @@ -0,0 +1,44 @@ +import { test, expect } from '@playwright/test'; + +test('has header', async ({ page }) => { + await page.goto('http://localhost:3000'); + + // The title should be visible + await expect(page).toHaveTitle(/Wookieepedia/); + + // Both people and planets tabs should be visible + await expect(page.getByRole('tab', { name: '🤖 PEOPLE' })).toBeVisible(); + await expect(page.getByRole('tab', { name: '🪐 PLANETS' })).toBeVisible(); +}); + + +test('people happy path', async ({ page }) => { + await page.goto('http://localhost:3000'); + + // Luke Skywalker should be visible + await expect(page.getByText('Luke Skywalker')).toBeVisible(); + await expect(page.getByText('Gasgano')).not.toBeVisible(); + + const peopleSearchBar = page.getByPlaceholder('Search people...'); + await peopleSearchBar.fill("gano"); + + // Gasgano should be visible while Luke Skywalker is not + await expect(page.getByText('Gasgano')).toBeVisible(); + await expect(page.getByText('Luke Skywalker')).not.toBeVisible(); +}); + +test('planets happy path', async ({ page }) => { + await page.goto('http://localhost:3000'); + + await page.getByRole('tab', { name: '🪐 PLANETS' }).click(); + + await expect(page.getByText('Tatooine')).toBeVisible(); + await expect(page.getByText('Felucia')).not.toBeVisible(); + + const planetsSearchBar = page.getByPlaceholder('Search planets...'); + await planetsSearchBar.fill("fe"); + + // Expect Felucia to be visible + await expect(page.getByText('Felucia')).toBeVisible(); + await expect(page.getByText('Tatooine')).not.toBeVisible(); +});