From 45bef07ac2b0a0292c201d6c1c6950686f2cabc4 Mon Sep 17 00:00:00 2001 From: Johan Guse Date: Mon, 30 Oct 2023 15:06:48 -0300 Subject: [PATCH] test: add first playwright test --- .gitignore | 8 ++ package.json | 2 + playwright.config.js | 108 +++++++++++++++++++++++++++ pnpm-lock.yaml | 35 +++++++++ src/components/auth/ButtonLogout.tsx | 4 +- tests/fixture.js | 41 ++++++++++ tests/homePage.spec.js | 26 +++++++ tests/navbarDesktop.spec.js | 27 +++++++ tsconfig.json | 3 +- 9 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 playwright.config.js create mode 100644 tests/fixture.js create mode 100644 tests/homePage.spec.js create mode 100644 tests/navbarDesktop.spec.js diff --git a/.gitignore b/.gitignore index 29d24e6..9a6dddf 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,11 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# tests +/test-results/ +/playwright-report/ +/playwright/.cache/ + +playwright/.auth +auth* \ No newline at end of file diff --git a/package.json b/package.json index a5413f9..10e009e 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint:format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\" --plugin-search-dir --ignore-path .gitignore", "lint:format:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\" --plugin-search-dir --ignore-path .gitignore", "lint": "pnpm lint:fix && pnpm lint:format", + "test": "playwright test", "stripe:listen": "stripe listen --forward-to localhost:3000/api/webhooks/stripe --latest", "postinstall": "prisma generate", "prisma:generate": "prisma generate", @@ -60,6 +61,7 @@ }, "devDependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.1.1", + "@playwright/test": "^1.39.0", "@types/eslint": "^8.44.6", "@types/negotiator": "^0.6.2", "@types/node": "20.8.7", diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..daa7c8a --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,108 @@ +/* eslint-disable notice/notice */ + +import { defineConfig, devices } from '@playwright/test' + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + + /* Maximum time one test can run for. */ + timeout: 15_000, + + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5_000, + }, + + /* 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: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://localhost: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', + + /* Project-specific settings. */ + 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: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // port: 3000, + // }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd59b55..f46e003 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,6 +103,9 @@ devDependencies: '@ianvs/prettier-plugin-sort-imports': specifier: ^4.1.1 version: 4.1.1(prettier@3.0.3) + '@playwright/test': + specifier: ^1.39.0 + version: 1.39.0 '@types/eslint': specifier: ^8.44.6 version: 8.44.6 @@ -622,6 +625,14 @@ packages: resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} dev: false + /@playwright/test@1.39.0: + resolution: {integrity: sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright: 1.39.0 + dev: true + /@prisma/client@5.5.2(prisma@5.5.2): resolution: {integrity: sha512-54XkqR8M+fxbzYqe+bIXimYnkkcGqgOh0dn0yWtIk6CQT4IUCAvNFNcQZwk2KqaLU+/1PHTSWrcHtx4XjluR5w==} engines: {node: '>=16.13'} @@ -2833,6 +2844,14 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3815,6 +3834,22 @@ packages: engines: {node: '>= 6'} dev: true + /playwright-core@1.39.0: + resolution: {integrity: sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==} + engines: {node: '>=16'} + hasBin: true + dev: true + + /playwright@1.39.0: + resolution: {integrity: sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright-core: 1.39.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /postcss-import@15.1.0(postcss@8.4.31): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} diff --git a/src/components/auth/ButtonLogout.tsx b/src/components/auth/ButtonLogout.tsx index 5c53c79..616cc31 100644 --- a/src/components/auth/ButtonLogout.tsx +++ b/src/components/auth/ButtonLogout.tsx @@ -55,12 +55,12 @@ export function LogoutBtn() { variant="tertiary" className="mb-4 mr-0 block justify-center lg:mb-0 lg:mr-4" > - + Login diff --git a/tests/fixture.js b/tests/fixture.js new file mode 100644 index 0000000..19a012b --- /dev/null +++ b/tests/fixture.js @@ -0,0 +1,41 @@ +import i18nEn from '@/locale/messages/en' +import i18nEs from '@/locale/messages/es' + +const i18nFixture = createI18nFixture({ + // i18n configuration options + options: { + debug: false, + ns: ['translations'], + supportedLngs: ['fr', 'es'], + cleanCode: true, + resources: { + en: { + translations: i18nEn, + }, + es: { + translations: i18nEs, + }, + }, + }, + // Fetch translations in every test or fetch once + // Default: true + cache: true, + // Run as auto fixture to be available through all tests by getI18nInstance() + // Default: true + auto: true, +}) + +export const testI18n = + baseTest.extend(i18nFixture).extend < + { i18nFix: i18n } > + { + i18nFix: async ({ i18n, locale }, use) => { + if (locale === 'es-ES') { + i18n.changeLanguage('es') + await use(i18n) + } else { + i18n.changeLanguage('fr') + await use(i18n) + } + }, + } diff --git a/tests/homePage.spec.js b/tests/homePage.spec.js new file mode 100644 index 0000000..9c0b729 --- /dev/null +++ b/tests/homePage.spec.js @@ -0,0 +1,26 @@ +const { test, expect } = require('@playwright/test') + +test.describe('Page tests', () => { + // berofe each test go to http://localhost:3000/es + test.beforeEach(async ({ page }) => { + await page.goto('http://localhost:3000/es') + }) + + // Test for title + test('has title', async ({ page }) => { + await expect(page).toHaveTitle('Johan Guse | Frontend Developer') + }) + + // Test for redirect link + test('get started link(first) redirects to signin or paths', async ({ + page, + }) => { + await page.locator('.btn-login').click() + + if (process.env.AUTH === '1') { + await expect(page).toHaveURL(/signin/) + } else { + await expect(page).toHaveURL(/paths/) + } + }) +}) diff --git a/tests/navbarDesktop.spec.js b/tests/navbarDesktop.spec.js new file mode 100644 index 0000000..41809f9 --- /dev/null +++ b/tests/navbarDesktop.spec.js @@ -0,0 +1,27 @@ +import { browserContext, expect, test } from '@playwright/test' + +test.skip(process.env.AUTH === '1') + +// skip if mobile +test.skip(({ isMobile }) => isMobile) + +// Test navbar on every page +test.afterEach(async ({ page }) => { + // Runs after each test by checking navbar components + + // skip if mobile + // test.skip(browserName != 'chromium', 'Mobile navbar different'); + + await expect(page.getByRole('link', { name: 'Login' })).toBeVisible() + await expect(page.getByRole('link', { name: 'Register' })).toBeVisible() +}) + +test('check navbar on /login', async ({ page }) => { + // ideally have this be authenticated + await page.goto('/login') +}) + +test('check navbar on /register', async ({ page }) => { + // ideally have this be authenticated + await page.goto('/register') +}) diff --git a/tsconfig.json b/tsconfig.json index a742346..280c6ce 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,7 +32,8 @@ "**/*.tsx", "**/*.cjs", "**/*.mjs", - ".next/types/**/*.ts" + ".next/types/**/*.ts", + "tests/fixture.js" ], "exclude": ["node_modules"] }