From 859fa4f2e195a2d3d79a4bd9d759ae04056c54f2 Mon Sep 17 00:00:00 2001 From: ilnaz <237x237@gmail.com> Date: Sun, 9 Feb 2025 09:57:04 +0300 Subject: [PATCH] feat: add playwright --- .gitignore | 8 ++- package-lock.json | 77 ++++++++++++++++++++--- package.json | 142 +++++++++++++++++++++--------------------- playwright.config.ts | 79 +++++++++++++++++++++++ tests/example.spec.ts | 26 ++++++++ 5 files changed, 252 insertions(+), 80 deletions(-) create mode 100644 playwright.config.ts create mode 100644 tests/example.spec.ts diff --git a/.gitignore b/.gitignore index 4664cf6..b6bf164 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,10 @@ dist .yarn/install-state.gz .pnp.* -.idea \ No newline at end of file +.idea + +# Playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/package-lock.json b/package-lock.json index b5f04e8..b32ef56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,9 @@ }, "devDependencies": { "@eslint/js": "^9.14.0", + "@playwright/test": "^1.50.1", "@stylistic/eslint-plugin": "^2.10.1", + "@types/node": "^22.13.1", "@types/react-dom": "^18.3.1", "eslint": "^9.14.0", "eslint-plugin-import": "^2.31.0", @@ -3619,6 +3621,21 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", + "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", + "dev": true, + "dependencies": { + "playwright": "1.50.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -4003,12 +4020,11 @@ "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" }, "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", - "license": "MIT", + "version": "22.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", + "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/parse-json": { @@ -12110,6 +12126,50 @@ "node": ">=4" } }, + "node_modules/playwright": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", + "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", + "dev": true, + "dependencies": { + "playwright-core": "1.50.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", + "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/popmotion": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", @@ -14382,10 +14442,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", diff --git a/package.json b/package.json index 3dc1c38..b160f1a 100644 --- a/package.json +++ b/package.json @@ -1,72 +1,74 @@ { - "name": "dry-wash", - "version": "0.5.0", - "description": "", - "main": "./src/index.tsx", - "scripts": { - "test": "jest -u", - "start": "brojs server --port=8099 --with-open-browser", - "build": "npm run clean && brojs build --dev", - "build:prod": "npm run clean && brojs build", - "clean": "rimraf dist", - "eslint": "npx eslint .", - "eslint:fix": "npx eslint . --fix", - "preversion": "npm run eslint" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@brojs/cli": "^1.8.4", - "@babel/core": "^7.26.7", - "@babel/preset-env": "^7.26.7", - "@babel/preset-react": "^7.26.3", - "@babel/preset-typescript": "^7.26.0", - "@chakra-ui/icons": "^2.2.4", - "@chakra-ui/react": "^2.10.5", - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "@fontsource/open-sans": "^5.1.0", - "@lottiefiles/react-lottie-player": "^3.5.4", - "@pbe/react-yandex-maps": "^1.2.5", - "@reduxjs/toolkit": "^2.5.0", - "@testing-library/dom": "^10.4.0", - "@testing-library/react": "^16.2.0", - "@types/react": "^18.3.12", - "babel-jest": "^29.7.0", - "dayjs": "^1.11.13", - "express": "^4.21.1", - "framer-motion": "^6.2.8", - "i18next": "^23.16.4", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "jest-fixed-jsdom": "^0.0.9", - "keycloak-js": "^23.0.7", - "msw": "^2.7.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-hook-form": "^7.53.2", - "react-i18next": "^15.1.1", - "react-icons": "^5.3.0", - "react-phone-number-input": "^3.4.9", - "react-redux": "^9.2.0", - "react-router-dom": "^6.27.0", - "ts-jest": "^29.2.5", - "ts-node": "^10.9.2" - }, - "devDependencies": { - "@eslint/js": "^9.14.0", - "@stylistic/eslint-plugin": "^2.10.1", - "@types/react-dom": "^18.3.1", - "eslint": "^9.14.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-react": "^7.37.2", - "globals": "^15.11.0", - "prettier": "3.3.3", - "typescript": "^5.7.3", - "typescript-eslint": "^8.12.2" - }, - "jest": { - "preset": "./jest-preset-it/jest-preset.ts" - } + "name": "dry-wash", + "version": "0.5.0", + "description": "", + "main": "./src/index.tsx", + "scripts": { + "test": "jest -u", + "start": "brojs server --port=8099 --with-open-browser", + "build": "npm run clean && brojs build --dev", + "build:prod": "npm run clean && brojs build", + "clean": "rimraf dist", + "eslint": "npx eslint .", + "eslint:fix": "npx eslint . --fix", + "preversion": "npm run eslint" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@babel/core": "^7.26.7", + "@babel/preset-env": "^7.26.7", + "@babel/preset-react": "^7.26.3", + "@babel/preset-typescript": "^7.26.0", + "@brojs/cli": "^1.8.4", + "@chakra-ui/icons": "^2.2.4", + "@chakra-ui/react": "^2.10.5", + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "@fontsource/open-sans": "^5.1.0", + "@lottiefiles/react-lottie-player": "^3.5.4", + "@pbe/react-yandex-maps": "^1.2.5", + "@reduxjs/toolkit": "^2.5.0", + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.2.0", + "@types/react": "^18.3.12", + "babel-jest": "^29.7.0", + "dayjs": "^1.11.13", + "express": "^4.21.1", + "framer-motion": "^6.2.8", + "i18next": "^23.16.4", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-fixed-jsdom": "^0.0.9", + "keycloak-js": "^23.0.7", + "msw": "^2.7.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.53.2", + "react-i18next": "^15.1.1", + "react-icons": "^5.3.0", + "react-phone-number-input": "^3.4.9", + "react-redux": "^9.2.0", + "react-router-dom": "^6.27.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2" + }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "@playwright/test": "^1.50.1", + "@stylistic/eslint-plugin": "^2.10.1", + "@types/node": "^22.13.1", + "@types/react-dom": "^18.3.1", + "eslint": "^9.14.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-react": "^7.37.2", + "globals": "^15.11.0", + "prettier": "3.3.3", + "typescript": "^5.7.3", + "typescript-eslint": "^8.12.2" + }, + "jest": { + "preset": "./jest-preset-it/jest-preset.ts" + } } diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..a05d8b5 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// 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/tests/example.spec.ts b/tests/example.spec.ts new file mode 100644 index 0000000..114f1bf --- /dev/null +++ b/tests/example.spec.ts @@ -0,0 +1,26 @@ +import { test, expect } from '@playwright/test'; + +test.beforeEach('check server is up', async ({ page }) => { + try { + await page.goto('http://localhost:8099/dry-wash'); + const makeOrderText = page.getByText('Сделать заказ', { exact: true }); + await expect(makeOrderText).toBeVisible(); + } catch (error) { + console.error('server not up'); + test.skip(); + } +}); + +test('login', async ({ page }) => { + await page.goto('http://localhost:8099/dry-wash/arm'); + await page.getByRole('textbox', { name: 'Username or email' }).click(); + await page + .getByRole('textbox', { name: 'Username or email' }) + .fill('237x237'); + await page.getByRole('textbox', { name: 'Password' }).click(); + await page.getByRole('textbox', { name: 'Password' }).fill(''); + await page.getByRole('button', { name: 'Sign In' }).click(); + await page.getByRole('heading', { name: 'Заказы' }).click(); + await page.getByRole('link', { name: 'Мастера' }).click(); + await page.getByRole('link', { name: 'Заказы' }).click(); +});