Skip to content

feat(release): ship the extension zips and settle two flaky fill tests - #17

Merged
rendyuwu merged 2 commits into
devfrom
feat/extension-release-zips
Oct 6, 2026
Merged

rendyuwu merged 2 commits into
devfrom
feat/extension-release-zips

Conversation

@rendyuwu

@rendyuwu rendyuwu commented Oct 3, 2026

Copy link
Copy Markdown
Owner

What

The two fill.spec.ts popup tests that failed intermittently in CI are
settled, and a tagged release now attaches subclave-chrome.zip and
subclave-firefox.zip to its draft, with install steps in the README.

Why

Closes #15. Closes #16.

How

Flaky tests (#15)

  • openPopup (extension/test/support/harness.ts) takes the page under test
    as front and brings it to the front before popup.html loads. Before, the
    popup loaded while its own tab was active and the test brought the fixture to
    the front afterwards. The popup's first get-state answers for the active
    tab, and chrome.tabs.query hides the url of a chrome-extension:// tab,
    so a get-state that ran first got "No active page". The popup asks only
    once, on mount, so no option ever rendered. The popup now loads in a
    background tab, and its first get-state sees the page under test.
  • Every popup call in fill.spec.ts and inline.spec.ts that has a page
    under test passes it, and the bringToFront() that followed the load is
    gone. The locked and not-running tests and the service worker restart test
    in save.spec.ts keep the bare call: they never read the active tab's URL.
  • generateAndFill fills the page before it calls save-login, so a log read
    taken as soon as #password held the generated value could run before the
    fake app had logged save-login. "generates a password, fills the signup
    form and saves a new entry" and "offers an update per match and keeps the
    entry id" now wait for the popup's "Password saved to Subclave" notice,
    which shows only after save-login has answered. The first of the two had
    the same race but had not failed in CI yet.
  • No change under extension/src/.

Extension zips in the release (#16)

  • New publish-extension job in .github/workflows/release.yml:
    needs: create-release, on ubuntu-latest, with the same pnpm 10 and
    Node 24 setup as publish-tauri and the build and zip commands from CI's
    extension job. An actions/github-script step uploads both zips by
    release_id, as tauri-action does: a re-run creates a second draft for the
    same tag, so a lookup by tag could pick the wrong one. A missing zip fails
    the job. It runs neither Playwright nor web-ext lint, because CI already
    ran both on the tagged commit.
  • README.md: "Install the browser extension", between Status and Build from
    source.
    • Chromium browsers: Load unpacked, the pinned ID, pairing and updating by
      hand.
    • Firefox: a temporary add-on on release and Beta, or a file install with
      xpinstall.signatures.required off on ESR, Developer Edition and Nightly.
  • KNOWN-LIMITS.md records the manual install and update until the extension
    is on the Chrome Web Store and signed by Mozilla. SUBCLAVE.md's release
    workflow mentions the zips.

Testing

  • Race 1, forced: a 1500 ms wait after the popup's goto in the old
    openPopup makes "a page load opens no connection and the first popup fill
    opens one" time out at getByRole('option') (fill.spec.ts:260), the CI
    failure. The same wait in the new openPopup passes.

  • Race 2, forced: a 1000 ms delay in the fake app's save-login makes both
    generate tests fail in both projects, with Expected: "entry-2",
    Received: undefined and Expected: "newuser", Received: undefined. With
    the notice wait, all four runs pass with the delay still in place. Neither
    delay is in this PR.

  • pnpm --filter subclave-extension test: 83/83.
    pnpm --filter subclave-extension test test/fill.spec.ts --repeat-each=5:
    140/140.

  • pnpm exec tsc --noEmit, pnpm run typecheck:extension and
    pnpm run format:check are clean.

  • The new job's build and zip commands, run locally: both zips hold
    manifest.json, background.js, content.js, popup.html, popup.js,
    popup.css and the icons. The unzipped Chrome build, loaded in Playwright's
    Chromium, gets the ID fbefjngeldidlcdilbigapddeimhklpn.

  • pnpm exec tsc --noEmit clean

  • Manual smoke-test of the affected feature

  • (If you touched src-tauri/) cargo check clean

  • (If UI) tested in pnpm tauri:dev (isolated dev data dir)

No changes under src-tauri/ and no app UI change.

Not tested yet:

  • The upload step and a real v* tag run. The next tag is the first real
    check of Releases ship no browser extension, so installing it means building from source #16's release half.
  • Pairing the released extension with a released app.
  • Either Firefox install path: whether Install Add-on From File accepts the
    .zip, and whether a temporary add-on stays paired across a restart. The
    README's "pair again" line holds either way.

Screenshots / GIFs

None. No UI change.

Notes for reviewer

  • The upload step has not run anywhere yet. Running release.yml by hand
    would create a real draft release, so it waits for the next tag.

Both failures were races in the tests, not in the extension.

openPopup loaded popup.html in a tab that was active at the time, and
the tests brought the fixture to the front only afterwards. The popup's
first get-state answers for the active tab, and chrome.tabs.query hides
the url of a chrome-extension:// tab, so a get-state that ran first got
"No active page" and the popup never listed an option. openPopup now
takes the page under test and brings it to the front before popup.html
loads, so the popup loads in a background tab and its first get-state
sees that page.

generateAndFill fills the page before it calls save-login, so a log read
taken as soon as #password held the generated value could run before the
fake app had logged save-login. Both generate tests now wait for the
popup's "Password saved to Subclave" notice, which shows only after
save-login has answered.

Closes #15
A tagged release shipped only the desktop installers, so getting the
extension meant building it from source or fetching a CI artifact that
expires after 7 days.

The new publish-extension job runs after create-release. It builds the
chrome and firefox targets, zips them with the same commands as CI's
extension job, and uploads subclave-chrome.zip and subclave-firefox.zip
into the draft by release_id, as tauri-action does: a re-run creates a
second draft for the same tag, so a lookup by tag could pick the wrong
one. It needs no Rust toolchain and no proxy build.

README.md gains an install section: Load unpacked on Chromium browsers,
with the pinned ID fbefjngeldidlcdilbigapddeimhklpn and the manual
update, and on Firefox a temporary add-on on release and Beta or a file
install with signatures off on ESR, Developer Edition and Nightly.
KNOWN-LIMITS.md records the manual install and update; SUBCLAVE.md's
release workflow mentions the zips.

Closes #16
@rendyuwu
rendyuwu merged commit d44d51f into dev Oct 6, 2026
7 checks passed
@rendyuwu
rendyuwu deleted the feat/extension-release-zips branch October 6, 2026 00:10
This was referenced Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Releases ship no browser extension, so installing it means building from source Extension E2E: two fill.spec.ts popup tests fail intermittently in CI

1 participant