diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e6ee76d..df9d7732 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,10 +190,18 @@ jobs: # The browser journeys (e2e/, 4l): the real backend and frontend started on a throwaway database, # driven in Playwright's own headless Chromium. On a developer's machine they run only when asked - # (e2e/README.md); here, on every pull request. - test-e2e: - name: Browser Journeys + # (e2e/README.md); here, on every pull request, split across four machines at once (Playwright's + # --shard), each with its own servers and database. Split test by test (--fully-parallel; each + # machine still runs one at a time) so the long graph file is shared out too: about 12 minutes in + # place of 27. + test-e2e-part: + name: Browser Journeys (${{ matrix.part }}/4) runs-on: ubuntu-latest + strategy: + # Every part runs to the end, so one failure never hides another's. + fail-fast: false + matrix: + part: [1, 2, 3, 4] steps: - name: Checkout Code uses: actions/checkout@v4 @@ -226,15 +234,26 @@ jobs: - name: Run the journeys working-directory: ./e2e - run: npx playwright test + run: npx playwright test --shard=${{ matrix.part }}/4 --fully-parallel - # What failed and why: screenshots, a trace of every step, and the HTML report. + # What failed and why: screenshots, a trace of every step, and the HTML report, one per part. - name: Keep the report of a failed run if: failure() uses: actions/upload-artifact@v4 with: - name: e2e-report + name: e2e-report-${{ matrix.part }} path: | e2e/playwright-report e2e/test-results retention-days: 14 + + # The one check named Browser Journeys, as before the split: it passes only when every part did, + # so a branch rule asking for that name keeps working. + test-e2e: + name: Browser Journeys + runs-on: ubuntu-latest + needs: test-e2e-part + if: always() + steps: + - name: Every part passed + run: test "${{ needs.test-e2e-part.result }}" = "success" diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f23c32..23c40e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,16 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added +- **The formula box on ROLLS and RESTS.** A roll's ADD and AGAINST, and a rest's refill amounts, + now get the same box as CHOICES. A line under each says it in words with what it comes to for + the sample character: "against your rolled stat · sample, rolling Strength, rolled stat 16: + target 16", "1d8 + CON modifier · sample CON modifier 2: 3 to 10". A roll's box rolls the first + stat in ROLLED BY. Dice in a rest are said as the least and most they can come to. A misspelt + name shows in red with a fix (`@thsi` offers USE @this). A typo in ADD or AGAINST used to count + as 0 at the table without a word. The formula button writes common ones for you: THE STAT + ROLLED and ITS MODIFIER on a roll, DICE and DICE AND A STAT on a rest (pick how many, which die + and which stat or formula). INSERT lists what each box can read, the stat being rolled first on + a roll. - **Subclasses follow their class's level.** A list a feature opens, like Fighter's Martial Archetype opening the archetypes at 3, now takes the level of the pick that opened it. Champion's features get AT LEVEL on CHOICES, grouped by level, and unlock by the Fighter's level: Improved @@ -683,6 +693,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Under the hood +- **The browser journeys run in four parts at once on CI.** Each pull request's journeys were run + one after another on one machine, about 27 minutes. They now run on four machines at once, each with + its own servers and database and a share of the tests, about 12 minutes. The check is still called + Browser Journeys and passes only when all four parts do; a failed part uploads its own report + (e2e-report-1 to 4). Nothing changes when they are run on a developer's machine. The builder's + journey now finds PUBLISH's message by its words, as the formula box added a second status line. - **Browser tests.** The first tests in a real browser (e2e/, Playwright): the real app started on a throwaway database, the GM signing in, building a system through the builder's screens, publishing it twice and switching the game to it; and a custom game played in two browsers at once, a player making a character in its words diff --git a/README.md b/README.md index f87bf9df..06b07701 100644 --- a/README.md +++ b/README.md @@ -449,7 +449,7 @@ CITY_NET/ │ │ ├── choices.js # A system's choices (7a1a; approved mockup builder-choices, 2026-10-27): the lists a character picks from (classes, backgrounds, feats), each named one and many, picked once, so many times or any, levelled or not, and MORE THAN ONCE for multiclassing; options with an optional requirement (a formula) and features, each unlocking at a level in a levelled list and doing any of: modifiers on a stat, formula or health field, uses refilled by a rest, rolls it gives, a change it lets a roll take, another list to pick from, or only words. Option and feature ids share one set; an option's level is read as @