diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..90b6b700 --- /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 636e58c3..e40f40c6 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,6 @@ dist # TernJS port file .tern-port +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/package-lock.json b/package-lock.json index 54168728..ff0c1683 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.0.0", "devDependencies": { "@cypress/code-coverage": "3.12.1", + "@playwright/test": "^1.38.1", + "@types/node": "^20.8.2", "cypress": "^13.3.0", "nyc": "15.1.0", "prettier": "^3.0.3", @@ -2072,6 +2074,21 @@ "node": ">= 8" } }, + "node_modules/@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "dev": true, + "dependencies": { + "playwright": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@types/eslint": { "version": "8.44.3", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.3.tgz", @@ -2109,9 +2126,9 @@ "peer": true }, "node_modules/@types/node": { - "version": "18.18.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.1.tgz", - "integrity": "sha512-3G42sxmm0fF2+Vtb9TJQpnjmP+uKlWvFa8KoEGquh4gqRmoUG/N0ufuhikw6HEsdG2G2oIKhog1GCTfz9v5NdQ==", + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", "dev": true }, "node_modules/@types/sinonjs__fake-timers": { @@ -3589,6 +3606,12 @@ "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, + "node_modules/cypress/node_modules/@types/node": { + "version": "18.18.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.3.tgz", + "integrity": "sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA==", + "dev": true + }, "node_modules/cypress/node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -4221,6 +4244,20 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "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/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -5579,6 +5616,36 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "dev": true, + "dependencies": { + "playwright-core": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/prettier": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", diff --git a/package.json b/package.json index 74225f0d..af66f594 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,42 @@ { - "name": "@smile_identity/web-page", - "version": "1.0.0", - "description": "Self Hosted Integration for Smile Identity on the Web", - "main": "inline.js", - "scripts": { - "build": "npm run instrument && npm run copy", - "prebuild:dist": "rm -rf dist", - "postbuild:dist": "npm run copy:dist", - "build:dist": "mkdir -p dist/js && echo src/js/*.js | xargs -n1 sh -c 'npx terser $1 --mangle --compress --output dist/js/$(basename $1 .js).min.js' argv0 && cp -r dist/js build", - "clean": "rm -rf build dist", - "copy": "cp -r src/* build && cp -r libs build && cp cypress/pages/*.html build", - "copy:dist": "cp -r src/* dist && cp -r libs dist", - "instrument": "nyc instrument src build", - "preinstrument": "npm run clean", - "prestart": "npm run build && npm run build:dist", - "start": "npx serve -p 8000 build", - "watch": "watch 'npm run prestart' src", - "test": "npx cypress run", - "lint:html": "npx prettier --write $(git ls-files '*.html')" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/smileidentity/hosted-web-integration.git" - }, - "keywords": [], - "author": "tams sokari ", - "bugs": { - "url": "https://github.com/smileidentity/hosted-web-integration/issues" - }, - "homepage": "https://github.com/smileidentity/hosted-web-integration#readme", - "devDependencies": { - "@cypress/code-coverage": "3.12.1", - "cypress": "^13.3.0", - "nyc": "15.1.0", - "prettier": "^3.0.3", - "serve": "14.2.1", - "terser": "5.20.0" - } + "name": "@smile_identity/web-page", + "version": "1.0.0", + "description": "Self Hosted Integration for Smile Identity on the Web", + "main": "inline.js", + "scripts": { + "build": "npm run instrument && npm run copy", + "prebuild:dist": "rm -rf dist", + "postbuild:dist": "npm run copy:dist", + "build:dist": "mkdir -p dist/js && echo src/js/*.js | xargs -n1 sh -c 'npx terser $1 --mangle --compress --output dist/js/$(basename $1 .js).min.js' argv0 && cp -r dist/js build", + "clean": "rm -rf build dist", + "copy": "cp -r src/* build && cp -r libs build && cp cypress/pages/*.html build", + "copy:dist": "cp -r src/* dist && cp -r libs dist", + "instrument": "nyc instrument src build", + "preinstrument": "npm run clean", + "prestart": "npm run build && npm run build:dist", + "start": "npx serve -p 8000 build", + "watch": "watch 'npm run prestart' src", + "test": "npx cypress run", + "lint:html": "npx prettier --write $(git ls-files '*.html')" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/smileidentity/hosted-web-integration.git" + }, + "keywords": [], + "author": "tams sokari ", + "bugs": { + "url": "https://github.com/smileidentity/hosted-web-integration/issues" + }, + "homepage": "https://github.com/smileidentity/hosted-web-integration#readme", + "devDependencies": { + "@cypress/code-coverage": "3.12.1", + "@playwright/test": "^1.38.1", + "@types/node": "^20.8.2", + "cypress": "^13.3.0", + "nyc": "15.1.0", + "prettier": "^3.0.3", + "serve": "14.2.1", + "terser": "5.20.0" + } } diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 00000000..b15af2e1 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,79 @@ +// @ts-check +const { defineConfig, devices } = require('@playwright/test'); + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * @see https://playwright.dev/docs/test-configuration + */ +module.exports = 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.js b/tests/example.spec.js new file mode 100644 index 00000000..40eddb86 --- /dev/null +++ b/tests/example.spec.js @@ -0,0 +1,19 @@ +// @ts-check +const { test, expect } = require('@playwright/test'); + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +});