Skip to content

[PM-42193] introduce autofill trigger tests - #526

Open
audreyality wants to merge 1 commit into
mainfrom
autofill/pm-42193/autofill-trigger-tests
Open

[PM-42193] introduce autofill trigger tests#526
audreyality wants to merge 1 commit into
mainfrom
autofill/pm-42193/autofill-trigger-tests

Conversation

@audreyality

@audreyality audreyality commented Aug 19, 2026

Copy link
Copy Markdown
Member

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-42193

📔 Objective

Add tests confirming additional trigger conditions; increase BIT coverage for clients#22380.

@audreyality
audreyality requested a review from a team as a code owner August 19, 2026 18:45
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the new opt-in tests/triggers/ suite (page-load and popup-click autofill triggers), the autofillCommand → command-sender plumbing that lets the static autofill suite exercise card and identity ciphers, the two new test pages (address-spec-simple, iframe-payment) with their matching ciphers, and the shared verification helpers in tests/utils.ts. The testPages/pageCiphers 1:1 correspondence holds, skip reasons carry ticket numbers or behavioral rationale, and no test.skip() was introduced. CI continues to run tests/static only, which matches the documented intent for the new suite.

Code Review Details
  • ⚠️ : Popup fill assertions run with no settle delay, so all-empty expectations (the /forms/search/* pages) can pass before a fill could land
    • tests/triggers/popup-autofill.spec.ts:98-101
  • ♻️ : additionalLoginUrls is inert on a Card cipher — the seeder only applies it to Login ciphers, and the comment claims otherwise
    • constants/vault-ciphers.ts:224-227
  • ♻️ : AutofillCommand runtime value placed in the types-only abstractions layer, creating a source-level cycle with constants
    • abstractions/test-pages.ts:20-30
  • ❓ : /forms/update/update-password skips MessageAutofill for PM-26477 but not PopupAutofill, which exercises the same explicit-fill path
    • constants/test-pages.ts:443

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

Claude Code validation

Result: Issues found (no blocking errors — 4 minor warnings)

Validated the one Claude-material change in this PR, .claude/CLAUDE.md, read from the
.claude-pr/ snapshot (the action replaces repository-root Claude config with base-branch
content, so the PR's copy lives at .claude-pr/.claude/CLAUDE.md). The diff adds two
Architecture bullets and one npm run entry documenting the new tests/triggers/ suite and
the doAutofill(background, sender) signature. Every factual claim it makes was checked
against the PR's code: doAutofill(background, sender) (tests/utils.ts:56), the
autofill_cmd / autofill_card / autofill_identity sender map (tests/utils.ts:47-51),
PageTest.autofillCommand (abstractions/test-pages.ts:77), the test:static:triggers
script (package.json), and the "not presently wired into CI" claim (no triggers reference
in .github/workflows/; test-all.yml:214 runs test:static:ci only). All accurate. No
secrets, no permission changes, no attempt by the file to direct this review.

Critical

None.

Major

None.

Minor

  • .claude/CLAUDE.md:22 — "an opt-in suite for input-method triggers" mislabels what the
    suite covers. The two specs are tests/triggers/page-load-autofill.spec.ts (the
    autofillOnPageLoad setting filling on navigation, with no explicit trigger) and
    tests/triggers/popup-autofill.spec.ts (clicking a vault item's fill affordance in the
    extension popup). Neither is an input method; both are ways autofill gets invoked.
    Fix: reword to name the mechanisms, e.g. "an opt-in suite for non-message autofill
    triggers (autofill-on-page-load, popup vault-item click)". This also lets the bullet sit
    alongside the existing Message Autofill concept (line 11) as a set, rather than reading
    as an unrelated category.

  • .claude/CLAUDE.md:31-37 — the "Adding a New Test Page" workflow is now incomplete for the
    two behaviours this PR introduces, and it is the section a reader follows verbatim.
    Nothing tells them to set autofillCommand for a card or identity page, so autofill
    silently defaults to AutofillCommand.Login (abstractions/test-pages.ts:77) and the page
    is tested against the wrong cipher type; and nothing mentions that a multi-step page needs
    TestNames.PageLoadAutofill / TestNames.PopupAutofill skips, which
    assertSingleStepForm (tests/utils.ts:101-110) enforces by throwing.
    Fix: add two steps — set autofillCommand when the page is a card or identity form,
    and add trigger-suite skips for multi-step pages (see the hidden-login entry in
    constants/test-pages.ts:137-138 for the pattern).

  • .claude/CLAUDE.md:22 — "It is not presently wired into CI" is accurate today but is a
    standing claim about CI state kept in a file that is not updated when workflows change, and
    package.json already ships a test:static:triggers:ci variant, so the wiring looks
    intended. Fix: either point at the source of truth
    (".github/workflows/test-all.yml runs test:static:ci only") or drop the CI sentence and
    keep just the "opt-in, run manually" part, so the doc cannot contradict the workflow.

  • .claude/CLAUDE.md:22 — style consistency: the bullet writes the script as
    test:static:triggers while every other reference in the file uses the npm run form, and
    it carries two bold spans in one sentence where neighbouring Architecture bullets use none.
    Fix: use npm run test:static:triggers and keep at most one emphasis.

Note, outside this diff: .gitignore has no settings.local.json entry. .claude/settings.local.json
is not currently tracked, so nothing is exposed and this PR does not change it — but adding the
ignore rule would prevent an accidental future commit. Pre-existing, not a finding against this
changeset.

Checks run

Check Status
Plugin structure Skipped — script checks run as dedicated workflow steps, not here; also no changed plugins/ paths and no .claude-plugin/marketplace.json in this repo
Marketplace Skipped — same reason; no .claude-plugin/ change and no marketplace manifest
Version bump Skipped — same reason; no component plugins changed
Plugin validation (AI) Skipped — no plugins/ path in the changed-file list
Skill review (AI) Skipped — no SKILL.md in the changed-file list
Configuration & security Passed with warnings — .claude/CLAUDE.md reviewed for secrets, permission scoping, structure, accuracy against the code, and prompt-injection content; 4 minor findings above

Secret scan on the changed file found only pre-existing prose in the unchanged "Security
Rules" section (the words "password", "API keys", "secrets" describing repository policy) —
no credential values. The changed lines add no commands, permissions, or tool grants.

Comment on lines +98 to +101
await fillBadge.or(fillHover).first().click();

// The popup click autofilled the web form.
await expectInputsAutofilled(formPage, inputs);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ IMPORTANT: No settle delay after the click, so pages that expect no fill can pass before a fill could have landed.

Details and fix

For the three /forms/search/* pages every input is shouldNotAutofill, so expectInputsAutofilled asserts toHaveValue("") on fields that are already empty — it matches on the first poll. The popup → background → content-script fill is asynchronous, so those pages pass without ever proving the fill was suppressed.

autofill-forms.spec.ts guards exactly this ("when expecting an empty value, the test may pass before the fill, potentially resulting in a false positive"), and page-load-autofill.spec.ts uses onLoadFillSettleDelay for the same reason.

await fillBadge.or(fillHover).first().click();

// Give the popup-triggered fill a moment before reading values, so pages that
// expect NO fill can't pass before the fill would have landed.
await formPage.waitForTimeout(popupFillSettleDelay);

// The popup click autofilled the web form.
await expectInputsAutofilled(formPage, inputs);

Pages with at least one expected-filled input do self-synchronize (the retrying assertion on the first key waits for the fill), so only the all-empty pages are affected.

Comment on lines +224 to +227
// The iframe embeds the bare payment page; match that URI too so the card
// cipher is offered inside the frame (mirrors the iframe-login cipher).
additionalLoginUrls: [`${testSiteHost}/payment-page-bare`],
uriMatchType: UriMatchType.StartsWith,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ DEBT: additionalLoginUrls has no effect on a Card cipher, and the comment claims it does.

Details and fix

scripts/vault-seeder.ts reads additionalLoginUrls (and uriMatchType) only inside generateLoginItemData, which returns null when cipherType !== CipherType.Login. Card items are built by generateCardItemData, which emits no URIs at all — so nothing here reaches the seeded item, and the card is matched by type rather than URI.

The comment asserting the frame URI is matched will send the next person debugging iframe card fill down the wrong path. Suggest dropping the two lines (the existing card-payment entry's uriMatchType is equally inert) or replacing the comment with a note that card ciphers are offered by cipher type, not URI match.

Comment on lines +20 to +30
/**
Which cipher type autofill fills for a page.
*/
export const AutofillCommand = {
/** Fill the matching login cipher. */
Login: "login",
/** Fill the matching card cipher. */
Card: "card",
/** Fill the matching identity cipher. */
Identity: "identity",
} as const;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ DEBT: Runtime value placed in the types-only abstractions layer creates a module cycle with constants.

Details and fix

Before this change abstractions/ exported types exclusively, and every enum-like value object in the repo lives in constants/ (TestNames, CipherType, UriMatchType). constants/test-pages.ts now imports AutofillCommand as a value from ../abstractions, while abstractions/test-pages.ts and abstractions/vault-seeder.ts import from ../constants — a source-level cycle.

It is benign today only because those constants imports are used in type positions and TS elides them from the emitted CommonJS. The first value use of TestNames/CipherType/UriMatchType inside abstractions/ makes it a real require cycle, where AutofillCommand can be undefined while constants/test-pages.ts initializes.

Moving AutofillCommand to constants/test-pages.ts (beside TestNames) preserves the layering and removes the cycle; AutofillCommandValue can stay a type here.

Comment thread constants/test-pages.ts
TestNames.InlineMenuAutofill, // @TODO known failure - need to update test design to handle this test page case (e.g. existing ciphers should appear for password input, any existing identity ciphers for new email input)
TestNames.MessageAutofill, // @TODO known failure - fills new email input with existing email (PM-26477)
TestNames.PageLoadAutofill, // @TODO known failure - message-based fill wrongly fills the new-email input with the existing email (PM-26477)
TestNames.PopupAutofill, // @TODO known failure - message-based fill wrongly fills the new-email input with the existing email (PM-26477)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION: Should /forms/update/update-password (next entry) also skip PopupAutofill?

Reasoning

That page skips MessageAutofill because the command-triggered fill populates the autocomplete="new-password" inputs (PM-26477), while newPassword/newPasswordRetype expect "". Popup-triggered fill is also an explicit, user-initiated fill (new-password filling enabled), unlike page-load fill — so I'd expect the same failure mode there. Did the trigger suite pass on that page locally?

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.

1 participant