mirror of
https://github.com/inventree/InvenTree.git
synced 2026-06-11 19:27:02 +00:00
fix(forntend): generate UI coverage again (#12066)
* Attempt to fix UI coverage * Update CI workflows: - use test sharding - Only upload coverage on master * Restore line * Simplify test * Simplify test matrix * Fix env vars * Adjust matrix * Adjust output names * Fix paths * Simplify qc_checks * Revert missing line * Simplify coverage calls * Run firefox test against port 8000 * Fix VITE_COVERAGE env var * Capture browser name in report output * Increase timeout again * Enhanced feedback from playwright startup * Split UI checks into separate file * Fix workflow deps * Shard chromium build * Adjust reporter type * Reduce uncessesary build steps * Tweak paths filter * Reduce retries * Also generate HTML reports * Tweak reporter output * Fix custom splash URLs * Fix envs for customization tests * Shard the firefox runner too * Ignore customization tests for firefox too * Don't upload if tests fail * Fix triggers * Remove merged test coverage * Pin download action * Error if no artifact files found * Update ignore dirs * Adjust baseFixtures * Fix for teardown in baseFixtures.ts * Fix path for coverage files * include hidden files
This commit is contained in:
@@ -106,7 +106,7 @@ runs:
|
|||||||
- name: Run invoke update
|
- name: Run invoke update
|
||||||
if: ${{ inputs.update == 'true' }}
|
if: ${{ inputs.update == 'true' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: invoke update --skip-backup --skip-static
|
run: invoke update --skip-backup --skip-static --no-frontend
|
||||||
- name: Collect static files
|
- name: Collect static files
|
||||||
if: ${{ inputs.static == 'true' }}
|
if: ${{ inputs.static == 'true' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -0,0 +1,306 @@
|
|||||||
|
# Playwright testing for frontend code
|
||||||
|
# Runs the following tests:
|
||||||
|
# - Playwright tests in Firefox (against compiled frontend code)
|
||||||
|
# - Playwright tests in Chromium (coverage enabled, against vite frontend code)
|
||||||
|
# - Build frontend code and upload as artifact
|
||||||
|
|
||||||
|
name: Frontend
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches-ignore: ["l10*"]
|
||||||
|
pull_request:
|
||||||
|
branches-ignore: ["l10*"]
|
||||||
|
|
||||||
|
env:
|
||||||
|
python_version: 3.11
|
||||||
|
node_version: 24
|
||||||
|
# The OS version must be set per job
|
||||||
|
server_start_sleep: 60
|
||||||
|
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
INVENTREE_DB_ENGINE: postgresql
|
||||||
|
INVENTREE_DB_NAME: inventree
|
||||||
|
INVENTREE_DB_HOST: "127.0.0.1"
|
||||||
|
INVENTREE_DB_PORT: 5432
|
||||||
|
INVENTREE_DB_USER: inventree_user
|
||||||
|
INVENTREE_DB_PASSWORD: inventree_password
|
||||||
|
INVENTREE_DEBUG: true
|
||||||
|
INVENTREE_PLUGINS_ENABLED: false
|
||||||
|
INVENTREE_MEDIA_ROOT: /home/runner/work/InvenTree/test_inventree_media
|
||||||
|
INVENTREE_STATIC_ROOT: /home/runner/work/InvenTree/test_inventree_static
|
||||||
|
INVENTREE_BACKUP_DIR: /home/runner/work/InvenTree/test_inventree_backup
|
||||||
|
INVENTREE_SITE_URL: http://localhost:8000
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
paths-filter:
|
||||||
|
name: Filter
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
frontend: ${{ steps.filter.outputs.frontend }}
|
||||||
|
force: ${{ steps.force.outputs.force }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # pin@v4.0.1
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
frontend:
|
||||||
|
- 'src/frontend/**'
|
||||||
|
- name: Is CI being forced?
|
||||||
|
run: echo "force=true" >> $GITHUB_OUTPUT
|
||||||
|
id: force
|
||||||
|
if: |
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'dependency') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'full-run')
|
||||||
|
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 60
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Environment Setup
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
npm: true
|
||||||
|
- name: Install dependencies
|
||||||
|
run: cd src/frontend && yarn install
|
||||||
|
- name: Build frontend
|
||||||
|
run: cd src/frontend && yarn run compile && yarn run lib && yarn run build
|
||||||
|
- name: Write version file - SHA
|
||||||
|
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
|
||||||
|
- name: Zip frontend
|
||||||
|
run: |
|
||||||
|
cd src/backend/InvenTree/web/static
|
||||||
|
zip -r frontend-build.zip web/ web/.vite
|
||||||
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
||||||
|
with:
|
||||||
|
name: frontend-build
|
||||||
|
path: src/backend/InvenTree/web/static/web
|
||||||
|
include-hidden-files: true
|
||||||
|
|
||||||
|
firefox:
|
||||||
|
name: Tests [Firefox ${{ matrix.shard }} / 2]
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 60
|
||||||
|
needs: ["build", "paths-filter"]
|
||||||
|
if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
shard: [1, 2]
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:17
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: inventree
|
||||||
|
POSTGRES_USER: inventree_user
|
||||||
|
POSTGRES_PASSWORD: inventree_password
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
options: >-
|
||||||
|
--health-cmd "pg_isready -U testuser"
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
|
||||||
|
env:
|
||||||
|
VITE_COVERAGE: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Environment Setup
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
npm: true
|
||||||
|
install: true
|
||||||
|
update: true
|
||||||
|
apt-dependency: gettext postgresql-client libpq-dev
|
||||||
|
pip-dependency: psycopg2
|
||||||
|
- name: Set up test data
|
||||||
|
run: |
|
||||||
|
invoke dev.setup-test -iv
|
||||||
|
invoke int.rebuild-thumbnails
|
||||||
|
- name: Install dependencies
|
||||||
|
run: invoke int.frontend-compile --extract
|
||||||
|
- name: Cache Playwright browsers
|
||||||
|
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0
|
||||||
|
id: playwright-cache
|
||||||
|
with:
|
||||||
|
path: ~/.cache/ms-playwright
|
||||||
|
key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }}
|
||||||
|
- name: Install Playwright browsers
|
||||||
|
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||||
|
run: cd src/frontend && npx playwright install --with-deps
|
||||||
|
- name: Install Playwright OS dependencies
|
||||||
|
if: steps.playwright-cache.outputs.cache-hit == 'true'
|
||||||
|
run: cd src/frontend && npx playwright install-deps
|
||||||
|
- name: Install Sample Plugin
|
||||||
|
run: |
|
||||||
|
pip install -U inventree-plugin-creator
|
||||||
|
create-inventree-plugin --default
|
||||||
|
cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build
|
||||||
|
- name: Run Playwright tests
|
||||||
|
id: tests
|
||||||
|
run: |
|
||||||
|
cd src/frontend
|
||||||
|
cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png
|
||||||
|
cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png
|
||||||
|
invoke static
|
||||||
|
env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox --shard=${{ matrix.shard }}/2
|
||||||
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
||||||
|
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
||||||
|
with:
|
||||||
|
name: playwright-report-firefox-${{ matrix.shard }}
|
||||||
|
path: src/frontend/playwright-report/
|
||||||
|
retention-days: 14
|
||||||
|
|
||||||
|
chromium:
|
||||||
|
name: Tests [Chromium ${{ matrix.shard }} / 4]
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 60
|
||||||
|
needs: ["build", "paths-filter"]
|
||||||
|
if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
shard: [1, 2, 3, 4]
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:17
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: inventree
|
||||||
|
POSTGRES_USER: inventree_user
|
||||||
|
POSTGRES_PASSWORD: inventree_password
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
options: >-
|
||||||
|
--health-cmd "pg_isready -U testuser"
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
|
||||||
|
env:
|
||||||
|
COVERAGE: true
|
||||||
|
VITE_COVERAGE: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Environment Setup
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
npm: true
|
||||||
|
install: true
|
||||||
|
update: true
|
||||||
|
apt-dependency: gettext postgresql-client libpq-dev
|
||||||
|
pip-dependency: psycopg2
|
||||||
|
- name: Set up test data
|
||||||
|
run: |
|
||||||
|
invoke dev.setup-test -iv
|
||||||
|
invoke int.rebuild-thumbnails
|
||||||
|
- name: Install dependencies
|
||||||
|
run: invoke int.frontend-compile --extract
|
||||||
|
- name: Cache Playwright browsers
|
||||||
|
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0
|
||||||
|
id: playwright-cache
|
||||||
|
with:
|
||||||
|
path: ~/.cache/ms-playwright
|
||||||
|
key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }}
|
||||||
|
- name: Install Playwright browsers
|
||||||
|
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||||
|
run: cd src/frontend && npx playwright install --with-deps
|
||||||
|
- name: Install Playwright OS dependencies
|
||||||
|
if: steps.playwright-cache.outputs.cache-hit == 'true'
|
||||||
|
run: cd src/frontend && npx playwright install-deps
|
||||||
|
- name: Install Sample Plugin
|
||||||
|
run: |
|
||||||
|
pip install -U inventree-plugin-creator
|
||||||
|
create-inventree-plugin --default
|
||||||
|
cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build
|
||||||
|
- name: Playwright [${{ matrix.shard }} / 4]
|
||||||
|
id: tests
|
||||||
|
run: |
|
||||||
|
cd src/frontend
|
||||||
|
npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4
|
||||||
|
- name: Playwright Report [${{ matrix.shard }} / 4]
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
||||||
|
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
||||||
|
with:
|
||||||
|
name: playwright-report-chromium-${{ matrix.shard }}
|
||||||
|
path: src/frontend/playwright-report/
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 7
|
||||||
|
- name: Upload Coverage Artifact [${{ matrix.shard }} / 4]
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
||||||
|
id: coverage-upload
|
||||||
|
if: ${{ !cancelled() && steps.tests.outcome != 'failure' }}
|
||||||
|
with:
|
||||||
|
name: coverage-${{ matrix.shard }}
|
||||||
|
path: src/frontend/.nyc_output/
|
||||||
|
if-no-files-found: error
|
||||||
|
include-hidden-files: true
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
# Recombine the coverage reports from the 4 shards, and upload to Codecov
|
||||||
|
coverage:
|
||||||
|
name: Merge coverage reports and upload to Codecov
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: chromium
|
||||||
|
timeout-minutes: 30
|
||||||
|
if: always()
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Environment Setup
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
npm: true
|
||||||
|
install: false
|
||||||
|
update: false
|
||||||
|
|
||||||
|
- name: Download Coverage Artifacts
|
||||||
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1
|
||||||
|
with:
|
||||||
|
pattern: coverage-*
|
||||||
|
path: all-coverage/
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Merge Coverage Reports
|
||||||
|
run: |
|
||||||
|
mkdir -p .nyc_output
|
||||||
|
cp all-coverage/*.json .nyc_output/ 2>/dev/null || true
|
||||||
|
npx nyc merge .nyc_output merged-coverage.json
|
||||||
|
npx nyc report \
|
||||||
|
--tempdir .nyc_output \
|
||||||
|
--reporter=lcov \
|
||||||
|
--reporter=text-summary \
|
||||||
|
--report-dir ./coverage \
|
||||||
|
|
||||||
|
- name: Upload coverage reports to Codecov
|
||||||
|
if: ${{ !cancelled() && github.ref == 'refs/heads/master' }}
|
||||||
|
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
slug: inventree/InvenTree
|
||||||
|
flags: web
|
||||||
|
files: ./coverage/lcov.info
|
||||||
@@ -664,133 +664,6 @@ jobs:
|
|||||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||||
invoke migrate
|
invoke migrate
|
||||||
|
|
||||||
web_ui:
|
|
||||||
name: Tests - Web UI
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
timeout-minutes: 60
|
|
||||||
needs: ["code-style", "paths-filter"]
|
|
||||||
if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:17
|
|
||||||
env:
|
|
||||||
POSTGRES_DB: inventree
|
|
||||||
POSTGRES_USER: inventree_user
|
|
||||||
POSTGRES_PASSWORD: inventree_password
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
options: >-
|
|
||||||
--health-cmd "pg_isready -U testuser"
|
|
||||||
--health-interval 10s
|
|
||||||
--health-timeout 5s
|
|
||||||
--health-retries 5
|
|
||||||
|
|
||||||
env:
|
|
||||||
INVENTREE_DB_ENGINE: postgresql
|
|
||||||
INVENTREE_DB_NAME: inventree
|
|
||||||
INVENTREE_DB_HOST: "127.0.0.1"
|
|
||||||
INVENTREE_DB_PORT: 5432
|
|
||||||
INVENTREE_DB_USER: inventree_user
|
|
||||||
INVENTREE_DB_PASSWORD: inventree_password
|
|
||||||
INVENTREE_DEBUG: true
|
|
||||||
INVENTREE_PLUGINS_ENABLED: false
|
|
||||||
VITE_COVERAGE_BUILD: true
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Environment Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
npm: true
|
|
||||||
install: true
|
|
||||||
update: true
|
|
||||||
apt-dependency: gettext postgresql-client libpq-dev
|
|
||||||
pip-dependency: psycopg2
|
|
||||||
- name: Set up test data
|
|
||||||
run: |
|
|
||||||
invoke dev.setup-test -iv
|
|
||||||
invoke int.rebuild-thumbnails
|
|
||||||
- name: Install dependencies
|
|
||||||
run: invoke int.frontend-compile --extract
|
|
||||||
- name: Cache Playwright browsers
|
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # pin@v5.0.5
|
|
||||||
id: playwright-cache
|
|
||||||
with:
|
|
||||||
path: ~/.cache/ms-playwright
|
|
||||||
key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }}
|
|
||||||
- name: Install Playwright browsers
|
|
||||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
|
||||||
run: cd src/frontend && npx playwright install --with-deps
|
|
||||||
- name: Install Playwright OS dependencies
|
|
||||||
if: steps.playwright-cache.outputs.cache-hit == 'true'
|
|
||||||
run: cd src/frontend && npx playwright install-deps
|
|
||||||
- name: Install Sample Plugin
|
|
||||||
run: |
|
|
||||||
pip install -U inventree-plugin-creator
|
|
||||||
create-inventree-plugin --default
|
|
||||||
cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build
|
|
||||||
- name: Run Playwright tests
|
|
||||||
id: tests
|
|
||||||
run: |
|
|
||||||
cd src/frontend
|
|
||||||
cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png
|
|
||||||
cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png
|
|
||||||
invoke static
|
|
||||||
env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" npx nyc playwright test --project=customization
|
|
||||||
npx nyc playwright test --project=chromium --project=firefox
|
|
||||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
|
||||||
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
|
||||||
with:
|
|
||||||
name: playwright-report
|
|
||||||
path: src/frontend/playwright-report/
|
|
||||||
retention-days: 14
|
|
||||||
- name: Report coverage
|
|
||||||
run: cd src/frontend && npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --exclude-after-remap false
|
|
||||||
- name: Upload coverage reports to Codecov
|
|
||||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
slug: inventree/InvenTree
|
|
||||||
flags: web
|
|
||||||
- name: Upload bundler info
|
|
||||||
env:
|
|
||||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
run: |
|
|
||||||
cd src/frontend
|
|
||||||
yarn install
|
|
||||||
yarn run build
|
|
||||||
|
|
||||||
web_ui_build:
|
|
||||||
name: Build - Web UI
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
timeout-minutes: 60
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Environment Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
npm: true
|
|
||||||
- name: Install dependencies
|
|
||||||
run: cd src/frontend && yarn install
|
|
||||||
- name: Build frontend
|
|
||||||
run: cd src/frontend && yarn run compile && yarn run lib && yarn run build
|
|
||||||
- name: Write version file - SHA
|
|
||||||
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
|
|
||||||
- name: Zip frontend
|
|
||||||
run: |
|
|
||||||
cd src/backend/InvenTree/web/static
|
|
||||||
zip -r frontend-build.zip web/ web/.vite
|
|
||||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
|
||||||
with:
|
|
||||||
name: frontend-build
|
|
||||||
path: src/backend/InvenTree/web/static/web
|
|
||||||
include-hidden-files: true
|
|
||||||
|
|
||||||
zizmor:
|
zizmor:
|
||||||
name: Security [Zizmor]
|
name: Security [Zizmor]
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ import { defineConfig, devices } from '@playwright/test';
|
|||||||
// Detect if running in CI
|
// Detect if running in CI
|
||||||
const IS_CI = !!process.env.CI;
|
const IS_CI = !!process.env.CI;
|
||||||
|
|
||||||
const MAX_WORKERS: number = 3;
|
|
||||||
const MAX_RETRIES: number = 3;
|
|
||||||
|
|
||||||
/* We optionally spin-up services based on the testing mode:
|
/* We optionally spin-up services based on the testing mode:
|
||||||
*
|
*
|
||||||
* Local Development:
|
* Local Development:
|
||||||
@@ -26,21 +23,28 @@ const MAX_RETRIES: number = 3;
|
|||||||
* - WORKERS = 1 (to avoid conflicts with HMR)
|
* - WORKERS = 1 (to avoid conflicts with HMR)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const BASE_URL: string = IS_CI
|
const BASE_URL: string =
|
||||||
? 'http://localhost:8000'
|
process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5173';
|
||||||
: 'http://localhost:5173';
|
|
||||||
|
// If running in "production" mode, we can use multiple workers to speed up the tests
|
||||||
|
const MAX_WORKERS: number = BASE_URL.endsWith('8000') ? 3 : 1;
|
||||||
|
const MAX_RETRIES: number = IS_CI ? 1 : 2;
|
||||||
|
|
||||||
console.log('Running Playwright Tests:');
|
console.log('Running Playwright Tests:');
|
||||||
console.log('- Base URL:', BASE_URL);
|
console.log('- Base URL:', BASE_URL);
|
||||||
|
console.log('- Max Workers:', MAX_WORKERS);
|
||||||
|
console.log('- Max Retries:', MAX_RETRIES);
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: './tests',
|
testDir: './tests',
|
||||||
fullyParallel: false,
|
fullyParallel: false,
|
||||||
timeout: 90000,
|
timeout: 90000,
|
||||||
forbidOnly: !!IS_CI,
|
forbidOnly: !!IS_CI,
|
||||||
retries: IS_CI ? MAX_RETRIES : 0,
|
retries: MAX_RETRIES,
|
||||||
workers: IS_CI ? MAX_WORKERS : 1,
|
workers: MAX_WORKERS,
|
||||||
reporter: IS_CI ? [['html', { open: 'never' }], ['github']] : 'list',
|
reporter: IS_CI
|
||||||
|
? [['html', { open: 'never' }], ['blob'], ['github']]
|
||||||
|
: 'list',
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
/* Configure projects for major browsers */
|
||||||
projects: [
|
projects: [
|
||||||
@@ -57,13 +61,6 @@ export default defineConfig({
|
|||||||
...devices['Desktop Firefox']
|
...devices['Desktop Firefox']
|
||||||
},
|
},
|
||||||
testIgnore: /customization/ // Ignore all tests in the "customization" folder for this project
|
testIgnore: /customization/ // Ignore all tests in the "customization" folder for this project
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'customization',
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Firefox']
|
|
||||||
},
|
|
||||||
testIgnore: /pui_.*\.spec\.ts/ // Ignore all "pui_*.spec.ts" tests for this project
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -89,7 +86,9 @@ export default defineConfig({
|
|||||||
INVENTREE_CORS_ORIGIN_ALLOW_ALL: 'True',
|
INVENTREE_CORS_ORIGIN_ALLOW_ALL: 'True',
|
||||||
INVENTREE_COOKIE_SAMESITE: 'False',
|
INVENTREE_COOKIE_SAMESITE: 'False',
|
||||||
INVENTREE_LOGIN_ATTEMPTS: '100',
|
INVENTREE_LOGIN_ATTEMPTS: '100',
|
||||||
INVENTREE_PLUGINS_MANDATORY: 'samplelocate'
|
INVENTREE_PLUGINS_MANDATORY: 'samplelocate',
|
||||||
|
INVENTREE_CUSTOM_SPLASH: 'img/playwright_custom_splash.png',
|
||||||
|
INVENTREE_CUSTOM_LOGO: 'img/playwright_custom_logo.png'
|
||||||
},
|
},
|
||||||
url: 'http://localhost:8000/api/',
|
url: 'http://localhost:8000/api/',
|
||||||
reuseExistingServer: IS_CI,
|
reuseExistingServer: IS_CI,
|
||||||
|
|||||||
@@ -2,9 +2,14 @@ import * as crypto from 'node:crypto';
|
|||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { test as baseTest } from '@playwright/test';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { type BrowserContext, test as baseTest } from '@playwright/test';
|
||||||
|
|
||||||
const istanbulCLIOutput = path.join(process.cwd(), '.nyc_output');
|
const frontendDir = path.resolve(
|
||||||
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
|
'..'
|
||||||
|
);
|
||||||
|
const istanbulCLIOutput = path.join(frontendDir, '.nyc_output');
|
||||||
const platform = os.platform();
|
const platform = os.platform();
|
||||||
let systemKeyVar: string;
|
let systemKeyVar: string;
|
||||||
if (platform === 'darwin') {
|
if (platform === 'darwin') {
|
||||||
@@ -19,16 +24,16 @@ export function generateUUID(): string {
|
|||||||
return crypto.randomBytes(16).toString('hex');
|
return crypto.randomBytes(16).toString('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const test = baseTest.extend({
|
async function setupCoverageCollection(context: BrowserContext) {
|
||||||
context: async ({ context }, use) => {
|
|
||||||
await context.addInitScript(() =>
|
await context.addInitScript(() =>
|
||||||
window.addEventListener('beforeunload', () =>
|
window.addEventListener('beforeunload', () =>
|
||||||
(window as any).collectIstanbulCoverage(
|
(window as any).collectIstanbulCoverage?.(
|
||||||
JSON.stringify((window as any).__coverage__)
|
JSON.stringify((window as any).__coverage__)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
await fs.promises.mkdir(istanbulCLIOutput, { recursive: true });
|
await fs.promises.mkdir(istanbulCLIOutput, { recursive: true });
|
||||||
|
try {
|
||||||
await context.exposeFunction(
|
await context.exposeFunction(
|
||||||
'collectIstanbulCoverage',
|
'collectIstanbulCoverage',
|
||||||
(coverageJSON: string) => {
|
(coverageJSON: string) => {
|
||||||
@@ -42,18 +47,68 @@ export const test = baseTest.extend({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await use(context);
|
} catch {
|
||||||
for (const page of context.pages()) {
|
// already exposed on this context (e.g. called twice for same context)
|
||||||
await page.evaluate(() =>
|
}
|
||||||
(window as any).collectIstanbulCoverage(
|
}
|
||||||
|
|
||||||
|
async function collectCoverageFromContext(context: BrowserContext) {
|
||||||
|
await Promise.allSettled(
|
||||||
|
context.pages().map(async (page) => {
|
||||||
|
try {
|
||||||
|
await Promise.race([
|
||||||
|
page.evaluate(() =>
|
||||||
|
(window as any).collectIstanbulCoverage?.(
|
||||||
JSON.stringify((window as any).__coverage__)
|
JSON.stringify((window as any).__coverage__)
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
new Promise((_, reject) =>
|
||||||
|
setTimeout(
|
||||||
|
() => reject(new Error('Coverage collection timeout')),
|
||||||
|
2000
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
} catch {
|
||||||
|
// page may already be closed or script execution can be blocked during teardown
|
||||||
|
}
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const test = baseTest.extend<{}, {}>({
|
||||||
|
// Wrap browser.newPage so contexts created via doCachedLogin also get coverage
|
||||||
|
browser: [
|
||||||
|
async ({ browser }, use) => {
|
||||||
|
const origNewPage = browser.newPage.bind(browser);
|
||||||
|
(browser as any).newPage = async (
|
||||||
|
options?: Parameters<typeof browser.newPage>[0]
|
||||||
|
) => {
|
||||||
|
const page = await origNewPage(options);
|
||||||
|
await setupCoverageCollection(page.context());
|
||||||
|
return page;
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await use(browser);
|
||||||
|
} finally {
|
||||||
|
(browser as any).newPage = origNewPage;
|
||||||
|
for (const context of browser.contexts()) {
|
||||||
|
await collectCoverageFromContext(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{ scope: 'worker' }
|
||||||
|
],
|
||||||
|
|
||||||
|
context: async ({ context }, use) => {
|
||||||
|
await setupCoverageCollection(context);
|
||||||
|
await use(context);
|
||||||
|
await collectCoverageFromContext(context);
|
||||||
|
},
|
||||||
|
|
||||||
// Ensure no errors are thrown in the console
|
// Ensure no errors are thrown in the console
|
||||||
page: async ({ page }, use) => {
|
page: async ({ page }, use) => {
|
||||||
const messages = [];
|
const messages: any[] = [];
|
||||||
page.on('console', (msg) => {
|
page.on('console', (msg) => {
|
||||||
const url = msg.location().url;
|
const url = msg.location().url;
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import test, { expect } from '@playwright/test';
|
import { expect, test } from '../baseFixtures';
|
||||||
import { navigate } from '../helpers';
|
import { navigate } from '../helpers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for user interface customization functionality.
|
* Tests for user interface customization functionality.
|
||||||
*
|
*
|
||||||
* Note: The correct environment variables must be set for these tests to work correctly. See "playwright.config.ts" for details.
|
* Note: The correct environment variables must be set for these tests to work correctly. See "playwright.config.ts" for details.
|
||||||
* These tests are designed to run in CI environments where specific environment variables are set to enable custom logos and splash screens. The tests verify that these customizations are correctly applied in the user interface.
|
* These tests are designed to run in CI environments where specific environment variables are set to enable custom logos and splash screens.
|
||||||
|
* The tests verify that these customizations are correctly applied in the user interface.
|
||||||
|
*
|
||||||
|
* If you are running these tests locally, ensure that you have the appropriate environment variables set to enable the customizations.
|
||||||
|
* You may need to modify the "webServer" configuration in "playwright.config.ts" to include the necessary environment variables for local testing.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
test('Customization - Splash', async ({ page }) => {
|
test('Customization - Splash', async ({ page }) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import test from '@playwright/test';
|
import { test } from '../baseFixtures';
|
||||||
import { loadTab } from '../helpers';
|
import { loadTab } from '../helpers';
|
||||||
import { doCachedLogin } from '../login';
|
import { doCachedLogin } from '../login';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import test from '@playwright/test';
|
import { test } from './baseFixtures';
|
||||||
import { stevenuser } from './defaults';
|
import { stevenuser } from './defaults';
|
||||||
import { globalSearch, loadTab, navigate } from './helpers';
|
import { globalSearch, loadTab, navigate } from './helpers';
|
||||||
import { doCachedLogin } from './login';
|
import { doCachedLogin } from './login';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/** Unit tests for form validation, rendering, etc */
|
|
||||||
import { expect, test } from 'playwright/test';
|
|
||||||
import { createApi } from './api';
|
import { createApi } from './api';
|
||||||
|
/** Unit tests for form validation, rendering, etc */
|
||||||
|
import { expect, test } from './baseFixtures';
|
||||||
import { stevenuser } from './defaults';
|
import { stevenuser } from './defaults';
|
||||||
import { navigate } from './helpers';
|
import { navigate } from './helpers';
|
||||||
import { doCachedLogin } from './login';
|
import { doCachedLogin } from './login';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import test from '@playwright/test';
|
import { test } from './baseFixtures';
|
||||||
import { stevenuser } from './defaults';
|
import { stevenuser } from './defaults';
|
||||||
import { doCachedLogin } from './login';
|
import { doCachedLogin } from './login';
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ test('Login - Failures', async ({ page }) => {
|
|||||||
await page.getByRole('button', { name: 'Log In' }).click();
|
await page.getByRole('button', { name: 'Log In' }).click();
|
||||||
await page.getByText('Login failed', { exact: true }).waitFor();
|
await page.getByText('Login failed', { exact: true }).waitFor();
|
||||||
await page.getByText('Check your input and try again').first().waitFor();
|
await page.getByText('Check your input and try again').first().waitFor();
|
||||||
await page.locator('#login').getByRole('button').click();
|
|
||||||
|
await page.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Navigate to the 'login' page
|
// Navigate to the 'login' page
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import test from 'playwright/test';
|
import { test } from './baseFixtures';
|
||||||
import { adminuser } from './defaults';
|
import { adminuser } from './defaults';
|
||||||
import { clickOnRowMenu, navigate } from './helpers';
|
import { clickOnRowMenu, navigate } from './helpers';
|
||||||
import { doCachedLogin } from './login';
|
import { doCachedLogin } from './login';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Tests for UI permissions checks
|
* Tests for UI permissions checks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import test from '@playwright/test';
|
import { test } from './baseFixtures';
|
||||||
import { adminuser, readeruser } from './defaults';
|
import { adminuser, readeruser } from './defaults';
|
||||||
import { clickOnRowMenu, loadTab } from './helpers';
|
import { clickOnRowMenu, loadTab } from './helpers';
|
||||||
import { doCachedLogin } from './login';
|
import { doCachedLogin } from './login';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import test from 'playwright/test';
|
import { test } from './baseFixtures';
|
||||||
|
|
||||||
import { adminuser } from './defaults.js';
|
import { adminuser } from './defaults.js';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default defineConfig(({ command, mode }) => {
|
|||||||
}),
|
}),
|
||||||
istanbul({
|
istanbul({
|
||||||
include: ['src/*', 'lib/*'],
|
include: ['src/*', 'lib/*'],
|
||||||
exclude: ['node_modules', 'test/'],
|
exclude: ['node_modules/', 'playwright/', 'tests/'],
|
||||||
extension: ['.js', '.ts', '.tsx'],
|
extension: ['.js', '.ts', '.tsx'],
|
||||||
requireEnv: true
|
requireEnv: true
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user