From 0148c0f0cf63c822ef8a45dc5918441d55e3babf Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Thu, 14 Sep 2023 18:03:35 +0300 Subject: [PATCH] feat: add-playwright --- .github/workflows/playwright.yml | 27 ++++++ .gitignore | 3 + apps/web/src/tests/not-authneticated.spec.ts | 31 +++++++ apps/web/src/tests/test-auth-flow.spec.ts | 31 +++++++ package-lock.json | 32 +++++++ package.json | 1 + playwright.config.ts | 91 ++++++++++++++++++++ playwright/.auth/user.json | 45 ++++++++++ 8 files changed, 261 insertions(+) create mode 100644 .github/workflows/playwright.yml create mode 100644 apps/web/src/tests/not-authneticated.spec.ts create mode 100644 apps/web/src/tests/test-auth-flow.spec.ts create mode 100644 playwright.config.ts create mode 100644 playwright/.auth/user.json diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 000000000..90b6b700d --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 246ce8bfe..7e38e4bda 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,6 @@ yarn-error.log* !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/apps/web/src/tests/not-authneticated.spec.ts b/apps/web/src/tests/not-authneticated.spec.ts new file mode 100644 index 000000000..2168d215c --- /dev/null +++ b/apps/web/src/tests/not-authneticated.spec.ts @@ -0,0 +1,31 @@ +import { expect, test } from '@playwright/test'; + +test.use({ storageState: { cookies: [], origins: [] } }); + +test('sign up with email and password', async ({ page }) => { + await page.goto('http://localhost:3000/signup'); + await page.getByLabel('Name').fill('John Doe'); + await page.getByLabel('Email').fill('johndoee@documenso.com'); + await page.getByLabel('Password').fill('my_secure_password'); + + const canvas = page.locator('canvas'); + const box = await canvas.boundingBox(); + + if (box) { + await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2); + await page.mouse.down(); + await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4); + await page.mouse.up(); + } + + await page.getByRole('button', { name: 'Sign Up' }).click(); +}); + +test('user can login with user and password', async ({ page }) => { + await page.goto('http://localhost:3000/signin'); + await page.getByLabel('Email').fill('johndoee@documenso.com'); + await page.getByLabel('Password').fill('my_secure_passwords'); + await page.getByRole('button', { name: 'Sign In' }).click(); + + await expect(page).toHaveURL('http://localhost:3000/documents'); +}); diff --git a/apps/web/src/tests/test-auth-flow.spec.ts b/apps/web/src/tests/test-auth-flow.spec.ts new file mode 100644 index 000000000..2dcbe667f --- /dev/null +++ b/apps/web/src/tests/test-auth-flow.spec.ts @@ -0,0 +1,31 @@ +import { expect, test } from '@playwright/test'; + +test.use({ storageState: { cookies: [], origins: [] } }); + +test('sign up with email and password', async ({ page }) => { + await page.goto('http://localhost:3000/signup'); + await page.getByLabel('Name').fill('John Doe'); + await page.getByLabel('Email').fill('johndoe2023@documenso.com'); + await page.getByLabel('Password').fill('my_secure_password'); + + const canvas = page.locator('canvas'); + const box = await canvas.boundingBox(); + + if (box) { + await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2); + await page.mouse.down(); + await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4); + await page.mouse.up(); + } + + await page.getByRole('button', { name: 'Sign Up' }).click(); +}); + +test('user can login with user and password', async ({ page }) => { + await page.goto('http://localhost:3000/signin'); + await page.getByLabel('Email').fill('johndoe2023@documenso.com'); + await page.getByLabel('Password').fill('my_secure_password'); + await page.getByRole('button', { name: 'Sign In' }).click(); + + await expect(page).toHaveURL('http://localhost:3000/documents'); +}); diff --git a/package-lock.json b/package-lock.json index 1fa10b764..c3f212b1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "devDependencies": { "@commitlint/cli": "^17.7.1", "@commitlint/config-conventional": "^17.7.0", + "@playwright/test": "^1.37.1", "dotenv": "^16.0.3", "dotenv-cli": "^7.2.1", "eslint": "^8.40.0", @@ -2554,6 +2555,25 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@playwright/test": { + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.1.tgz", + "integrity": "sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.37.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, "node_modules/@prisma/client": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.0.0.tgz", @@ -12451,6 +12471,18 @@ "node": ">= 6" } }, + "node_modules/playwright-core": { + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.1.tgz", + "integrity": "sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/postcss": { "version": "8.4.27", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", diff --git a/package.json b/package.json index 3b2fbf6ca..145abfa35 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "devDependencies": { "@commitlint/cli": "^17.7.1", "@commitlint/config-conventional": "^17.7.0", + "@playwright/test": "^1.37.1", "dotenv": "^16.0.3", "dotenv-cli": "^7.2.1", "eslint": "^8.40.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 000000000..e5aae93e4 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,91 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './apps/web/src/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: 'setup', testMatch: /.*\.setup\.ts/ }, + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + // Use prepared auth state. + storageState: 'playwright/.auth/user.json', + }, + dependencies: ['setup'], + }, + + { + name: 'firefox', + use: { + ...devices['Desktop Firefox'], + // Use prepared auth state. + storageState: 'playwright/.auth/user.json', + }, + dependencies: ['setup'], + }, + { + name: 'webkit', + use: { + ...devices['Desktop Safari'], + storageState: 'playwright/.auth/user.json', + }, + dependencies: ['setup'], + }, + ], + + /* 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/playwright/.auth/user.json b/playwright/.auth/user.json new file mode 100644 index 000000000..396f420a5 --- /dev/null +++ b/playwright/.auth/user.json @@ -0,0 +1,45 @@ +{ + "cookies": [ + { + "name": "next-auth.csrf-token", + "value": "49a064cb88e494947823c51109973374e5fb9727cedd59b373d75a75fd00f81e%7Cda5d2a2fd2eee8b271d52ee5557a75d0d73502dc43fe4c2b53722145471672d0", + "domain": "localhost", + "path": "/", + "expires": -1, + "httpOnly": true, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "next-auth.callback-url", + "value": "http%3A%2F%2Flocalhost%3A3000%2Fdocuments", + "domain": "localhost", + "path": "/", + "expires": -1, + "httpOnly": true, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "next-auth.session-token", + "value": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..RMToD8_cweHpgPJY.tojHFkmlMUGMLIMtYBd0B6t2SS0pyvpLAuKSYN4AGj-jLxJlBYXOxQIucnCOLo7TSbUoyoV4GCLEBUh5OhmJ4yiP8oedWg8FRtYisT67ejzMVdAOy5_4FvTG-QlE6SxCz8JVAfTkKh1FQfI2f0xY7LCCHPkEsObTcGj1hLXh.DFIVOs5R0Dl5mwpJFNoCpg", + "domain": "localhost", + "path": "/", + "expires": 1697186468.813095, + "httpOnly": true, + "secure": false, + "sameSite": "Lax" + } + ], + "origins": [ + { + "origin": "http://localhost:3000", + "localStorage": [ + { + "name": "nextauth.message", + "value": "{\"event\":\"session\",\"data\":{\"trigger\":\"getSession\"},\"timestamp\":1694594468}" + } + ] + } + ] +} \ No newline at end of file