Repository navigation
More Director 8.5 fixes on top of #245: score, sound, inks, text, input, shaders #465
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: E2E Tests | ||
|
Check warning on line 1 in .github/workflows/e2e.yml
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
| pull_request_target: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
| inputs: | ||
| ref: | ||
| description: 'Branch, tag, or commit SHA to test' | ||
| required: false | ||
| type: string | ||
| default: '' | ||
| pr_number: | ||
| description: 'PR number to test (for fork PRs — posts statuses on the PR head SHA)' | ||
| required: false | ||
| type: string | ||
| default: '' | ||
| rebase_on_main: | ||
| description: 'Rebase on main before running tests' | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| statuses: write | ||
| env: | ||
| CARGO_TERM_COLOR: always | ||
| TEST_ASSETS_URL: ${{ secrets.TEST_ASSETS_URL }} | ||
| HABBO_V7_USERNAME: ${{ secrets.HABBO_V7_USERNAME }} | ||
| HABBO_V7_PASSWORD: ${{ secrets.HABBO_V7_PASSWORD }} | ||
| HABBO_V7_INFO_HOST: ${{ secrets.HABBO_V7_INFO_HOST }} | ||
| HABBO_V7_INFO_PORT: ${{ secrets.HABBO_V7_INFO_PORT }} | ||
| HABBO_V7_WS_SSL: ${{ vars.HABBO_V7_WS_SSL }} | ||
| HABBO_V7_WS_PATH: ${{ vars.HABBO_V7_WS_PATH }} | ||
| HABBO_V26_SSO_TICKET: ${{ secrets.HABBO_V26_SSO_TICKET }} | ||
| HABBO_V26_INFO_HOST: ${{ secrets.HABBO_V26_INFO_HOST }} | ||
| HABBO_V26_INFO_PORT: ${{ secrets.HABBO_V26_INFO_PORT }} | ||
| HABBO_V26_WS_SSL: ${{ vars.HABBO_V26_WS_SSL }} | ||
| HABBO_V26_WS_PATH: ${{ vars.HABBO_V26_WS_PATH }} | ||
| HABBO_V31_SSO_TICKET: ${{ secrets.HABBO_V31_SSO_TICKET }} | ||
| HABBO_V31_INFO_HOST: ${{ secrets.HABBO_V31_INFO_HOST }} | ||
| HABBO_V31_INFO_PORT: ${{ secrets.HABBO_V31_INFO_PORT }} | ||
| HABBO_V31_WS_SSL: ${{ vars.HABBO_V31_WS_SSL }} | ||
| HABBO_V31_WS_PATH: ${{ vars.HABBO_V31_WS_PATH }} | ||
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
| S3_BUCKET: ${{ secrets.S3_BUCKET }} | ||
| S3_REGION: ${{ secrets.S3_REGION }} | ||
| jobs: | ||
| native: | ||
| name: Native tests | ||
| runs-on: ubuntu-latest | ||
| # Skip pull_request runs from forks (they have no secrets and would fail); | ||
| # those go through pull_request_target instead. | ||
| if: | | ||
| github.event_name == 'push' || | ||
| github.event_name == 'workflow_dispatch' || | ||
| (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || | ||
| (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) | ||
| # pull_request_target from a fork pauses on this environment until a | ||
| environment: ${{ github.event_name == 'pull_request_target' && 'fork-pr-tests' || '' }} | ||
| steps: | ||
| - name: Resolve PR head | ||
| id: resolve_pr | ||
| if: inputs.pr_number != '' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_NUMBER: ${{ inputs.pr_number }} | ||
| with: | ||
| script: | | ||
| const pr = await github.rest.pulls.get({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: parseInt(process.env.PR_NUMBER, 10), | ||
| }); | ||
| core.setOutput('sha', pr.data.head.sha); | ||
| core.setOutput('ref', `refs/pull/${pr.data.number}/head`); | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| # For pull_request_target, github.ref points at the BASE branch — we | ||
| # need to explicitly check out the PR's merge ref to test the PR code. | ||
| ref: ${{ github.event_name == 'pull_request_target' && format('refs/pull/{0}/merge', github.event.pull_request.number) || steps.resolve_pr.outputs.ref || inputs.ref || github.ref }} | ||
| submodules: true | ||
| fetch-depth: 0 | ||
| allow-unsafe-pr-checkout: true | ||
| - name: Post pending status | ||
| if: inputs.pr_number != '' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_SHA: ${{ steps.resolve_pr.outputs.sha }} | ||
| with: | ||
| script: | | ||
| await github.rest.repos.createCommitStatus({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| sha: process.env.PR_SHA, | ||
| state: 'pending', | ||
| context: 'E2E / native', | ||
| target_url: `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, | ||
| }); | ||
| - name: Rebase on main | ||
| if: inputs.rebase_on_main | ||
| run: | | ||
| git config user.name "github-actions" | ||
| git config user.email "github-actions@github.com" | ||
| git fetch origin main | ||
| git rebase origin/main | ||
| - name: Download test assets | ||
| run: | | ||
| if [ -z "$TEST_ASSETS_URL" ]; then | ||
| echo "::error::TEST_ASSETS_URL secret is not set" | ||
| exit 1 | ||
| fi | ||
| curl -fSL "$TEST_ASSETS_URL" -o assets.zip | ||
| unzip -qo assets.zip -d public/ | ||
| - name: Cargo fetch | ||
| working-directory: ./vm-rust | ||
| run: cargo fetch | ||
| # `run-native-tests.mjs` always runs `generate-snapshot-report.mjs` | ||
| # afterwards, and that imports `pngjs`. Without an install step this job | ||
| # ended every run on ERR_MODULE_NOT_FOUND, whatever the tests did. | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: npm | ||
| - name: Install npm dependencies | ||
| run: npm ci | ||
| - name: Run native e2e tests | ||
| id: native_tests | ||
| continue-on-error: true | ||
| run: node scripts/run-native-tests.mjs | ||
| - name: Generate snapshot diff grid | ||
| if: always() | ||
| run: | | ||
| sudo apt-get install -yq imagemagick >/dev/null 2>&1 || true | ||
| bash scripts/build-diff-grid.sh vm-rust/tests/snapshots /tmp/diff-report | ||
| - name: Upload diff grid to S3 | ||
| if: always() | ||
| run: | | ||
| if [ -z "$S3_BUCKET" ] || [ ! -f /tmp/diff-report/diff-grid.png ]; then exit 0; fi | ||
| KEY="dirplayer/snapshots/${GITHUB_RUN_ID}/native-$(sha256sum /tmp/diff-report/diff-grid.png | cut -c1-12).png" | ||
| aws s3 cp /tmp/diff-report/diff-grid.png "s3://${S3_BUCKET}/${KEY}" --content-type image/png | ||
| echo "https://${S3_BUCKET}.s3.${S3_REGION:-us-east-1}.amazonaws.com/${KEY}" > /tmp/diff-report/image-url.txt | ||
| - name: Upload snapshot report to S3 | ||
| id: upload_report | ||
| if: always() | ||
| run: | | ||
| if [ -z "$S3_BUCKET" ] || [ ! -f test-results/snapshot-report/index.html ]; then exit 0; fi | ||
| PREFIX="dirplayer/snapshots/${GITHUB_RUN_ID}/native-report" | ||
| [ -d test-results/snapshot-report/images ] && \ | ||
| aws s3 sync test-results/snapshot-report/images/ "s3://${S3_BUCKET}/${PREFIX}/images/" | ||
| [ -d test-results/snapshot-report/suites ] && \ | ||
| aws s3 sync test-results/snapshot-report/suites/ "s3://${S3_BUCKET}/${PREFIX}/suites/" \ | ||
| --content-type "text/html; charset=utf-8" | ||
| aws s3 cp test-results/snapshot-report/index.html \ | ||
| "s3://${S3_BUCKET}/${PREFIX}/index.html" --content-type "text/html; charset=utf-8" | ||
| echo "url=https://${S3_BUCKET}.s3.${S3_REGION:-us-east-1}.amazonaws.com/${PREFIX}/index.html" >> "$GITHUB_OUTPUT" | ||
| - name: Upload test artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: native-test-results | ||
| path: | | ||
| vm-rust/tests/snapshots/output/ | ||
| vm-rust/tests/snapshots/diff/ | ||
| /tmp/diff-report/ | ||
| test-results/ | ||
| retention-days: 7 | ||
| - name: Post snapshot test report on PR | ||
| if: always() && (github.event_name == 'pull_request' || github.event_name == 'pull_request_target' || inputs.pr_number != '') | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_NUMBER: ${{ inputs.pr_number }} | ||
| REPORT_URL: ${{ steps.upload_report.outputs.url }} | ||
| with: | ||
| script: | | ||
| const script = require('./scripts/post-snapshot-comment.cjs'); | ||
| const prNumber = process.env.PR_NUMBER ? parseInt(process.env.PR_NUMBER, 10) : context.issue.number; | ||
| await script({ github, context, label: 'native', artifactName: 'native-test-results', prNumber, reportUrl: process.env.REPORT_URL || null }); | ||
| - name: Post final status | ||
| if: always() && inputs.pr_number != '' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_SHA: ${{ steps.resolve_pr.outputs.sha }} | ||
| OUTCOME: ${{ steps.native_tests.outcome }} | ||
| REPORT_URL: ${{ steps.upload_report.outputs.url }} | ||
| with: | ||
| script: | | ||
| const state = process.env.OUTCOME === 'success' ? 'success' : 'failure'; | ||
| const targetUrl = process.env.REPORT_URL || | ||
| `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | ||
| await github.rest.repos.createCommitStatus({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| sha: process.env.PR_SHA, | ||
| state, | ||
| context: 'E2E / native', | ||
| target_url: targetUrl, | ||
| }); | ||
| - name: Fail if native tests failed | ||
| if: steps.native_tests.outcome == 'failure' | ||
| run: exit 1 | ||
| browser: | ||
| name: Browser tests | ||
| runs-on: ubuntu-latest | ||
| if: | | ||
| github.event_name == 'push' || | ||
| github.event_name == 'workflow_dispatch' || | ||
| (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || | ||
| (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) | ||
| environment: ${{ github.event_name == 'pull_request_target' && 'fork-pr-tests' || '' }} | ||
| steps: | ||
| - name: Resolve PR head | ||
| id: resolve_pr | ||
| if: inputs.pr_number != '' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_NUMBER: ${{ inputs.pr_number }} | ||
| with: | ||
| script: | | ||
| const pr = await github.rest.pulls.get({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: parseInt(process.env.PR_NUMBER, 10), | ||
| }); | ||
| core.setOutput('sha', pr.data.head.sha); | ||
| core.setOutput('ref', `refs/pull/${pr.data.number}/head`); | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.event_name == 'pull_request_target' && format('refs/pull/{0}/merge', github.event.pull_request.number) || steps.resolve_pr.outputs.ref || inputs.ref || github.ref }} | ||
| submodules: true | ||
| fetch-depth: 0 | ||
| allow-unsafe-pr-checkout: true | ||
| - name: Post pending status | ||
| if: inputs.pr_number != '' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_SHA: ${{ steps.resolve_pr.outputs.sha }} | ||
| with: | ||
| script: | | ||
| await github.rest.repos.createCommitStatus({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| sha: process.env.PR_SHA, | ||
| state: 'pending', | ||
| context: 'E2E / browser', | ||
| target_url: `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, | ||
| }); | ||
| - name: Rebase on main | ||
| if: inputs.rebase_on_main | ||
| run: | | ||
| git config user.name "github-actions" | ||
| git config user.email "github-actions@github.com" | ||
| git fetch origin main | ||
| git rebase origin/main | ||
| - name: Install wasm target | ||
| run: rustup target add wasm32-unknown-unknown | ||
| - name: Install wasm-bindgen-cli | ||
| run: | | ||
| WASM_BINDGEN_VERSION=$(cargo metadata --manifest-path vm-rust/Cargo.toml --format-version 1 | \ | ||
| python3 -c "import sys,json; pkgs=json.load(sys.stdin)['packages']; print(next(p['version'] for p in pkgs if p['name']=='wasm-bindgen'))") | ||
| cargo install wasm-bindgen-cli --version "$WASM_BINDGEN_VERSION" | ||
| - name: Download test assets | ||
| run: | | ||
| if [ -z "$TEST_ASSETS_URL" ]; then | ||
| echo "::error::TEST_ASSETS_URL secret is not set" | ||
| exit 1 | ||
| fi | ||
| curl -fSL "$TEST_ASSETS_URL" -o assets.zip | ||
| unzip -qo assets.zip -d public/ | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: npm | ||
| - name: Install npm dependencies | ||
| run: npm ci | ||
| - name: Install Playwright browsers | ||
| run: npx playwright install --with-deps chromium | ||
| - name: Install Microsoft Core Fonts | ||
| run: | | ||
| echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true" | sudo debconf-set-selections | ||
| sudo apt-get install -y ttf-mscorefonts-installer | ||
| sudo fc-cache -fv | ||
| - name: Cargo fetch | ||
| working-directory: ./vm-rust | ||
| run: cargo fetch | ||
| - name: Build and copy Ruffle | ||
| working-directory: ./vm-rust | ||
| run: npm run build-ruffle && npm run copy-ruffle | ||
| - name: Build xtras (bobba-xtra, example-xtra, …) | ||
| # The xtra registry resolves to wasms under public/ — built fresh | ||
| # here from xtras/<name>/ so browser-side `new(xtra "…")` calls | ||
| # have something to load. | ||
| run: npm run build-xtras | ||
| - name: Build and run browser e2e tests | ||
| id: browser_tests | ||
| continue-on-error: true | ||
| run: node scripts/run-browser-tests.mjs | ||
| - name: Generate snapshot diff grid | ||
| if: always() | ||
| run: | | ||
| sudo apt-get install -yq imagemagick >/dev/null 2>&1 || true | ||
| bash scripts/build-diff-grid.sh vm-rust/tests/snapshots /tmp/diff-report | ||
| - name: Upload diff grid to S3 | ||
| if: always() | ||
| run: | | ||
| if [ -z "$S3_BUCKET" ] || [ ! -f /tmp/diff-report/diff-grid.png ]; then exit 0; fi | ||
| KEY="dirplayer/snapshots/${GITHUB_RUN_ID}/browser-$(sha256sum /tmp/diff-report/diff-grid.png | cut -c1-12).png" | ||
| aws s3 cp /tmp/diff-report/diff-grid.png "s3://${S3_BUCKET}/${KEY}" --content-type image/png | ||
| echo "https://${S3_BUCKET}.s3.${S3_REGION:-us-east-1}.amazonaws.com/${KEY}" > /tmp/diff-report/image-url.txt | ||
| - name: Upload snapshot report to S3 | ||
| id: upload_report | ||
| if: always() | ||
| run: | | ||
| if [ -z "$S3_BUCKET" ] || [ ! -f test-results/snapshot-report/index.html ]; then exit 0; fi | ||
| PREFIX="dirplayer/snapshots/${GITHUB_RUN_ID}/browser-report" | ||
| [ -d test-results/snapshot-report/images ] && \ | ||
| aws s3 sync test-results/snapshot-report/images/ "s3://${S3_BUCKET}/${PREFIX}/images/" | ||
| [ -d test-results/snapshot-report/suites ] && \ | ||
| aws s3 sync test-results/snapshot-report/suites/ "s3://${S3_BUCKET}/${PREFIX}/suites/" \ | ||
| --content-type "text/html; charset=utf-8" | ||
| aws s3 cp test-results/snapshot-report/index.html \ | ||
| "s3://${S3_BUCKET}/${PREFIX}/index.html" --content-type "text/html; charset=utf-8" | ||
| echo "url=https://${S3_BUCKET}.s3.${S3_REGION:-us-east-1}.amazonaws.com/${PREFIX}/index.html" >> "$GITHUB_OUTPUT" | ||
| - name: Upload test artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: browser-test-results | ||
| path: | | ||
| vm-rust/tests/snapshots/output/ | ||
| vm-rust/tests/snapshots/diff/ | ||
| /tmp/diff-report/ | ||
| test-results/ | ||
| retention-days: 7 | ||
| - name: Post snapshot test report on PR | ||
| if: always() && (github.event_name == 'pull_request' || github.event_name == 'pull_request_target' || inputs.pr_number != '') | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_NUMBER: ${{ inputs.pr_number }} | ||
| REPORT_URL: ${{ steps.upload_report.outputs.url }} | ||
| with: | ||
| script: | | ||
| const script = require('./scripts/post-snapshot-comment.cjs'); | ||
| const prNumber = process.env.PR_NUMBER ? parseInt(process.env.PR_NUMBER, 10) : context.issue.number; | ||
| await script({ github, context, label: 'browser', artifactName: 'browser-test-results', prNumber, reportUrl: process.env.REPORT_URL || null }); | ||
| - name: Post final status | ||
| if: always() && inputs.pr_number != '' | ||
| uses: actions/github-script@v7 | ||
| env: | ||
| PR_SHA: ${{ steps.resolve_pr.outputs.sha }} | ||
| OUTCOME: ${{ steps.browser_tests.outcome }} | ||
| REPORT_URL: ${{ steps.upload_report.outputs.url }} | ||
| with: | ||
| script: | | ||
| const state = process.env.OUTCOME === 'success' ? 'success' : 'failure'; | ||
| const targetUrl = process.env.REPORT_URL || | ||
| `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | ||
| await github.rest.repos.createCommitStatus({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| sha: process.env.PR_SHA, | ||
| state, | ||
| context: 'E2E / browser', | ||
| target_url: targetUrl, | ||
| }); | ||
| - name: Fail if browser tests failed | ||
| if: steps.browser_tests.outcome == 'failure' | ||
| run: exit 1 | ||