diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml new file mode 100644 index 0000000000..cd6e2e7742 --- /dev/null +++ b/.github/workflows/playwright.yaml @@ -0,0 +1,44 @@ +name: Playwright Tests + +env: + pip-version: 24.2 + +on: + push: + branches: [auth, main] + pull_request: + branches: [auth, main] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + working-directory: ./app + run: npm install -g pnpm && pnpm install + - name: Install Playwright Browsers + working-directory: ./app + run: pnpm exec playwright install --with-deps + - name: Build the app + working-directory: ./app + run: pnpm run build + - uses: actions/setup-python@v5 + with: + python-version: 3.12 + - name: Install Phoenix + run: | + python -m pip install --upgrade pip==${{ env.pip-version }} + pip install . + - name: Run Playwright tests + working-directory: ./app + run: pnpm exec playwright test + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: app/playwright-report/ + retention-days: 30 diff --git a/app/.gitignore b/app/.gitignore index d875631601..960a0f90da 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,3 +1,7 @@ node_modules dist -stats.html \ No newline at end of file +stats.html +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/app/package.json b/app/package.json index 55d3b3422d..1148df97c8 100644 --- a/app/package.json +++ b/app/package.json @@ -50,11 +50,13 @@ }, "devDependencies": { "@emotion/react": "^11.11.4", + "@playwright/test": "^1.47.0", "@types/d3-format": "^3.0.4", "@types/d3-scale-chromatic": "^3.0.3", "@types/d3-time-format": "^4.0.3", "@types/jest": "^29.5.12", "@types/lodash": "^4.17.7", + "@types/node": "^22.5.4", "@types/react": "18.2.48", "@types/react-dom": "^18.3.0", "@types/react-relay": "^16.0.6", @@ -88,11 +90,14 @@ "build:static": "cpy ./static ../src/phoenix/server", "build:relay": "relay-compiler", "test": "jest --config ./jest.config.js", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", "dev": "pnpm run dev:server & pnpm run build:static && pnpm run build:relay && vite", "dev:auth": "export PHOENIX_ENABLE_AUTH=true && export PHOENIX_SECRET=sa18f44bd9b6b4b0606e58a2d03d09039aee8283e0074c6517fda58577a07dd#A && pnpm run dev:server & pnpm run build:static && pnpm run build:relay && vite", "dev:ui": "pnpm run build:static && pnpm run build:relay && vite", - "dev:server:init": "python -m phoenix.server.main --dev serve --with-fixture=chatbot --with-project=demo_llama_index --force-fixture-ingestion", "dev:server": "python -m phoenix.server.main --dev serve", + "dev:server:test": "node ./tests/utils/testServer.mjs", + "dev:server:init": "python -m phoenix.server.main --dev serve --with-fixture=chatbot --with-project=demo_llama_index --force-fixture-ingestion", "typecheck": "tsc --noEmit", "lint": "eslint ./src", "prettier": "prettier --write './src/**/*'", diff --git a/app/playwright.config.ts b/app/playwright.config.ts new file mode 100644 index 0000000000..2aeb43d25e --- /dev/null +++ b/app/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'; +// 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://localhost:6006", + + /* 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: /global\.setup\.ts/, + }, + { + 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: "pnpm run dev:server:test", + url: "http://localhost:6006", + reuseExistingServer: false, // !process.env.CI, + }, +}); diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index 8c6ec25f12..f3a0ca5661 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -138,6 +138,9 @@ importers: '@emotion/react': specifier: ^11.11.4 version: 11.11.4(@types/react@18.2.48)(react@18.2.0) + '@playwright/test': + specifier: ^1.47.0 + version: 1.47.0 '@types/d3-format': specifier: ^3.0.4 version: 3.0.4 @@ -153,6 +156,9 @@ importers: '@types/lodash': specifier: ^4.17.7 version: 4.17.7 + '@types/node': + specifier: ^22.5.4 + version: 22.5.4 '@types/react': specifier: 18.2.48 version: 18.2.48 @@ -179,7 +185,7 @@ importers: version: 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.1(vite@5.3.3(@types/node@20.14.11)) + version: 4.3.1(vite@5.3.3(@types/node@22.5.4)) cpy-cli: specifier: ^5.0.0 version: 5.0.0 @@ -203,7 +209,7 @@ importers: version: 16.9.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + version: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 @@ -221,16 +227,16 @@ importers: version: 5.12.0(rollup@4.18.1) ts-jest: specifier: ^29.2.2 - version: 29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(esbuild@0.23.0)(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(typescript@5.4.5) + version: 29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(esbuild@0.23.0)(jest@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0))(typescript@5.4.5) typescript: specifier: ~5.4.5 version: 5.4.5 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.11) + version: 5.3.3(@types/node@22.5.4) vite-plugin-relay: specifier: ^2.1.0 - version: 2.1.0(babel-plugin-relay@17.0.0)(vite@5.3.3(@types/node@20.14.11)) + version: 2.1.0(babel-plugin-relay@17.0.0)(vite@5.3.3(@types/node@22.5.4)) packages: @@ -1012,6 +1018,11 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@playwright/test@1.47.0': + resolution: {integrity: sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==} + engines: {node: '>=18'} + hasBin: true + '@react-aria/breadcrumbs@3.5.13': resolution: {integrity: sha512-G1Gqf/P6kVdfs94ovwP18fTWuIxadIQgHsXS08JEVcFVYMjb9YjqnEBaohUxD1tq2WldMbYw53ahQblT4NTG+g==} peerDependencies: @@ -1599,8 +1610,8 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@20.14.11': - resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} + '@types/node@22.5.4': + resolution: {integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==} '@types/offscreencanvas@2019.7.3': resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} @@ -2682,6 +2693,11 @@ 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] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3882,6 +3898,16 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + playwright-core@1.47.0: + resolution: {integrity: sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.47.0: + resolution: {integrity: sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==} + engines: {node: '>=18'} + hasBin: true + polished@4.3.1: resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} engines: {node: '>=10'} @@ -4566,8 +4592,8 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -5522,7 +5548,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -5535,14 +5561,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + jest-config: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -5567,7 +5593,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -5585,7 +5611,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.14.11 + '@types/node': 22.5.4 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -5607,7 +5633,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -5696,7 +5722,7 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.14.11 + '@types/node': 22.5.4 '@types/yargs': 15.0.19 chalk: 4.1.2 @@ -5705,7 +5731,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.14.11 + '@types/node': 22.5.4 '@types/yargs': 17.0.32 chalk: 4.1.2 @@ -5773,6 +5799,10 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@playwright/test@1.47.0': + dependencies: + playwright: 1.47.0 + '@react-aria/breadcrumbs@3.5.13(react@18.2.0)': dependencies: '@react-aria/i18n': 3.11.1(react@18.2.0) @@ -6526,7 +6556,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 '@types/hast@3.0.4': dependencies: @@ -6549,7 +6579,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 '@types/tough-cookie': 4.0.5 parse5: 7.1.2 @@ -6561,9 +6591,9 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@20.14.11': + '@types/node@22.5.4': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 '@types/offscreencanvas@2019.7.3': {} @@ -6764,14 +6794,14 @@ snapshots: '@use-gesture/core': 10.3.1 react: 18.2.0 - '@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@20.14.11))': + '@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@22.5.4))': dependencies: '@babel/core': 7.24.9 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.9) '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.9) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.3.3(@types/node@20.14.11) + vite: 5.3.3(@types/node@22.5.4) transitivePeerDependencies: - supports-color @@ -7270,13 +7300,13 @@ snapshots: p-filter: 3.0.0 p-map: 6.0.0 - create-jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0): + create-jest@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + jest-config: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -7947,6 +7977,9 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -8448,7 +8481,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3(babel-plugin-macros@3.1.0) @@ -8468,16 +8501,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0): + jest-cli@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0): dependencies: '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + create-jest: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + jest-config: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -8487,7 +8520,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0): + jest-config@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0): dependencies: '@babel/core': 7.24.9 '@jest/test-sequencer': 29.7.0 @@ -8512,7 +8545,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -8542,7 +8575,7 @@ snapshots: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 20.14.11 + '@types/node': 22.5.4 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -8556,7 +8589,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -8566,7 +8599,7 @@ snapshots: dependencies: '@jest/types': 26.6.2 '@types/graceful-fs': 4.1.9 - '@types/node': 20.14.11 + '@types/node': 22.5.4 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -8586,7 +8619,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.14.11 + '@types/node': 22.5.4 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -8625,7 +8658,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -8662,7 +8695,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -8690,7 +8723,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 cjs-module-lexer: 1.3.1 collect-v8-coverage: 1.0.2 @@ -8710,7 +8743,7 @@ snapshots: jest-serializer@26.6.2: dependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 graceful-fs: 4.2.11 jest-snapshot@29.7.0: @@ -8741,7 +8774,7 @@ snapshots: jest-util@26.6.2: dependencies: '@jest/types': 26.6.2 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 graceful-fs: 4.2.11 is-ci: 2.0.0 @@ -8750,7 +8783,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -8769,7 +8802,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.11 + '@types/node': 22.5.4 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -8778,23 +8811,23 @@ snapshots: jest-worker@26.6.2: dependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 merge-stream: 2.0.0 supports-color: 7.2.0 jest-worker@29.7.0: dependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0): + jest@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0): dependencies: '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + jest-cli: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -9572,6 +9605,14 @@ snapshots: dependencies: find-up: 4.1.0 + playwright-core@1.47.0: {} + + playwright@1.47.0: + dependencies: + playwright-core: 1.47.0 + optionalDependencies: + fsevents: 2.3.2 + polished@4.3.1: dependencies: '@babel/runtime': 7.24.8 @@ -10257,12 +10298,12 @@ snapshots: dependencies: typescript: 5.4.5 - ts-jest@29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(esbuild@0.23.0)(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(typescript@5.4.5): + ts-jest@29.2.2(@babel/core@7.24.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.9))(esbuild@0.23.0)(jest@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0))(typescript@5.4.5): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0) + jest: 29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -10344,7 +10385,7 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@5.26.5: {} + undici-types@6.19.8: {} unified@11.0.5: dependencies: @@ -10469,21 +10510,21 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-relay@2.1.0(babel-plugin-relay@17.0.0)(vite@5.3.3(@types/node@20.14.11)): + vite-plugin-relay@2.1.0(babel-plugin-relay@17.0.0)(vite@5.3.3(@types/node@22.5.4)): dependencies: '@babel/core': 7.24.9 babel-plugin-relay: 17.0.0 - vite: 5.3.3(@types/node@20.14.11) + vite: 5.3.3(@types/node@22.5.4) transitivePeerDependencies: - supports-color - vite@5.3.3(@types/node@20.14.11): + vite@5.3.3(@types/node@22.5.4): dependencies: esbuild: 0.21.5 postcss: 8.4.39 rollup: 4.18.1 optionalDependencies: - '@types/node': 20.14.11 + '@types/node': 22.5.4 fsevents: 2.3.3 w3c-keyname@2.2.8: {} diff --git a/app/src/pages/auth/ResetPasswordForm.tsx b/app/src/pages/auth/ResetPasswordForm.tsx index 10e487eddf..39ef11dddf 100644 --- a/app/src/pages/auth/ResetPasswordForm.tsx +++ b/app/src/pages/auth/ResetPasswordForm.tsx @@ -106,7 +106,7 @@ export function ResetPasswordForm() { fieldState: { invalid, error }, }) => ( { + await page.goto("http://localhost:6006/login"); + + await page.getByLabel("Email").fill("admin@localhost"); + await page.getByLabel("Password").fill("admin"); + await page.getByRole("button", { name: "Login" }).click(); + + // Reset the password + await page.waitForURL("**/reset-password"); + await page.getByLabel("Old Password").fill("admin"); + await page.getByLabel("New Password").fill("admin123"); + await page.getByLabel("Confirm Password").fill("admin123"); + await page.getByRole("button", { name: "Reset Password" }).click(); +}); + +test("create a member", async ({ page }) => { + await page.goto("http://localhost:6006/login"); + + await page.getByLabel("Email").fill("admin@localhost"); + await page.getByLabel("Password").fill("admin123"); + await page.getByRole("button", { name: "Login" }).click(); + await page.waitForURL("**/projects/**"); + // Reset the password + await page.goto("/settings"); + await page.waitForURL("**/settings"); + await page.getByRole("button", { name: "Add User" }).click(); + + // Add the user + await page.getByLabel("Email").fill("member@localhost.com"); + await page.getByLabel("Password").fill("member123"); + await page.getByLabel("member", { exact: true }).click(); + await page.getByRole("option", { name: "member" }).click(); + await page + .getByRole("dialog") + .getByRole("button", { name: "Add User" }) + .click(); +}); diff --git a/app/tests/utils/testServer.mjs b/app/tests/utils/testServer.mjs new file mode 100644 index 0000000000..ff0daf099c --- /dev/null +++ b/app/tests/utils/testServer.mjs @@ -0,0 +1,27 @@ +//@ts-check +/* eslint-disable no-console */ +import { exec } from "child_process"; +import fs from "fs"; +import * as crypto from "node:crypto"; +import os from "os"; +import path from "path"; +import process from "process"; + +const appPrefix = "phoenix"; +const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), appPrefix)); + +// Set environment variables for the server +process.env["PHOENIX_WORKING_DIR"] = tmpDir; +process.env["PHOENIX_ENABLE_AUTH"] = "True"; +process.env["PHOENIX_SECRET"] = crypto.randomBytes(32).toString("hex"); + +console.log("Phoenix test server starting..."); +console.log("PHOENIX_SECRET: ", process.env["PHOENIX_SECRET"]); +console.log("PHOENIX_WORKING_DIR: ", process.env["PHOENIX_WORKING_DIR"]); + +// Execute the server +// TODO: Might have to force install the phoenix server +const childProcess = exec("python -m phoenix.server.main serve"); + +childProcess.stdout.pipe(process.stdout); +childProcess.stderr.pipe(process.stderr);