Skip to content

Feat/integration test setup#622

Open
hildebrandttk wants to merge 2 commits into
bulwarkmail:mainfrom
hildebrandttk:feat/integration-test-setup
Open

Feat/integration test setup#622
hildebrandttk wants to merge 2 commits into
bulwarkmail:mainfrom
hildebrandttk:feat/integration-test-setup

Conversation

@hildebrandttk

@hildebrandttk hildebrandttk commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a self-contained, dockerized end-to-end integration harness that drives the
Bulwark webmail against a real Stalwart mail server with Playwright, plus a first
regression test for issue #569 (the composer's From dropdown should offer shared/
group account identities).

This is the reusable base branch that the unified-mailbox feature builds on: it
carries only harness infrastructure and app test-hooks — no feature code — so it
sits directly on main and can be reviewed/merged on its own.

Changes

Integration harness (integration/) — commit 17d1658

  • Stalwart backend: docker-compose.yml + stalwart/ image with a
    declarative two-phase bootstrap (entrypoint.sh, plan-bootstrap.ndjson,
    plan-accounts.ndjson.tpl): default domain + admin, the alice/bob/carol test
    mailboxes, submission/IMAP listeners, permissive CORS, cleartext auth for the
    dev lanes, inbound throttles disabled. stalwart-cli is host-prefetched and
    COPYed into the image (apt/CDN are unreachable at build time).
  • Webmail: webmail.Dockerfile runs next dev — the production CSP pins
    connect-src 'self' https: and would block the browser's plaintext cross-
    origin JMAP calls — with the unifiedCrossAccountEnabled policy gate mounted.
  • Playwright: playwright.integration.config.ts + global-setup/teardown
    bring the stack up (or reuse a running one via IT_NO_DOCKER=1); run-tests.sh
    runs the suite inside the official Playwright container (host browsers are
    unsupported by the 1.59 bundles) over host networking.
  • Helpers: a dependency-free SMTP submission client, a small JMAP client for
    seeding/inspecting server state, and page helpers (login, add/switch account,
    locale-independent folder-counter reads via data-testid).
  • Specs 01–03: login, single-account sync, multi-account (account-scoped
    Unified Mailbox).
  • App test-hooks: focused data-testids on the mail UI (folder rows +
    counters, email list items, account switcher, composer). examples/ and
    integration/ are excluded from tsconfig/eslint/.dockerignore.
  • The multi-account spec a delivery to a background account bumps the Unified Inbox counter is test.fixme'd on this branch only: the background-push
    counter fix it exercises lives in the unified-mailbox feature commits, not
    here. It is re-enabled on feat/unified-mailbox-account-scope.

Issue #569 — composer From offers shared/group identities — commit 7fcff64

  • Provisioning, before first login: a Stalwart Group team@example.org is
    created in plan-accounts, and carol is made a member via
    User.memberGroupIds in the entrypoint (the group's server-assigned id is
    resolved after apply, mirroring the existing DOMAIN_ID step). carol — not
    alice/bob — so the single-/multi-account sync specs keep an unshared env.
  • Spec 04-shared-identity: logs in as the group member and asserts the
    composer's From selector offers team@example.org; a JMAP server-side guard
    first confirms the group account and its team@ identity are reachable in the
    member's session.
  • App: data-testid="composer-from" on the From <select> and its single-
    identity <span> fallback.
  • Helpers: GROUP config, openComposer/composerFromOptions, and JMAP
    client accounts/sharedAccountNames (Identity/get needs the submission
    capability, not mail).

Related Issues

Closes #569

The pre-login group-membership scenario already works with no app change:
when a user is provisioned into the group before first login, Stalwart returns
the group's team@ address as an identity on the member's own account, so the
app's normal single-account identity load yields identities.length > 1 and the
From <select> renders team@. The test is green. #569's remaining gap is the
other shapes — an ACL-shared folder from another user, or a second connected
account — whose identities are not merged into the primary account and so still
need the multi-account identity loader to include shared accounts.

##+ Tests

  • Integration: specs 01–04 pass in the Playwright container (03's background-
    counter case is fixme'd here, see above). Run: integration/run-tests.sh
    (or npm run test:integration). A stale Stalwart volume must be reset first
    (cd integration && docker compose down -v) so the group is provisioned.
  • App tsc --noEmit clean.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactor / code quality improvement
  • Chore / dependency update / CI change

Checklist

  • I have read the Contributing Guide
  • My code follows the project's code style and conventions
  • I have run npm run typecheck && npm run lint and there are no errors
  • The build passes (npm run build)
  • I have tested my changes locally
  • I have added or updated documentation if needed
  • I have updated translations (locales/) if my changes affect user-facing text
  • I have included screenshots or a screen recording for UI changes

Screenshots / Demo

04-shared-identity.webm

Notes for Reviewers

Branches directly off main (511f9e5). The feature branch
feat/unified-mailbox-account-scope shares this branch's harness setup commit
(17d1658) as its base, so merge this MR first.

Add an end-to-end integration harness that runs the webmail against a real
Stalwart mail server in Docker and drives it with Playwright, focused on the
mail/folder synchronisation behaviour (unread/total counters, folder-list
sync, account-scoped Unified Mailbox) that the unified-mailbox work touches.

- integration/ stack: Stalwart (declarative bootstrap: alice/bob/carol,
  submission + IMAP listeners, permissive CORS) + webmail (dev mode, so the
  browser's plaintext cross-origin JMAP calls aren't blocked by the prod CSP).
- Helpers: dependency-free SMTP submit client, JMAP client for seeding /
  inspecting server state, and page helpers (login, add/switch account,
  locale-independent folder-counter reads).
- Specs: login, single-account sync (receive/read/move/delete/folder-create/
  burst) and multi-account (per-account isolation + cross-account Unified
  Inbox aggregation + background-account delivery). 12 tests, all green.
- Add focused data-testid hooks to the mail UI (folder rows + counters, email
  list items, account switcher, composer) for stable selectors.
- Exclude examples/ and integration/ from tsconfig/eslint/.dockerignore.
…arkmail#569)

Provision a Stalwart group (team@example.org) with carol as a member before her
first login, and assert the composer's From selector offers the group address.
This confirms the group-membership scenario of bulwarkmail#569 already works out of the
box: Stalwart returns the group's send-as identity on the member's own account,
so the app's normal single-account identity load surfaces it (identities.length
> 1 -> the From <select> renders with team@).

- stalwart: create the `team` Group in plan-accounts and add carol via
  User.memberGroupIds in the entrypoint (id resolved after apply, like
  DOMAIN_ID). carol, not alice/bob, so the sync specs stay unshared.
- helpers: GROUP config, openComposer/composerFromOptions, and JmapClient
  accounts + sharedAccountNames (Identity/get needs the submission capability).
- composer: add data-testid="composer-from" to the From <select> and its
  single-identity <span> fallback.

Ref: bulwarkmail#569
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.

[Bug]: Composer "From" dropdown does not include identities from shared/group accounts

1 participant