mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-01 16:12:02 +00:00
Both 04-all-mail and 04-shared-identity shared the same 04 prefix. Shift shared-identity and everything after it up by one (05-shared-identity … 12-cross-view-retain), leaving 04-all-mail as the sole 04 spec. Pure file renames; no content changes.
77 lines
3.2 KiB
TypeScript
77 lines
3.2 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
||
import { ACCOUNTS, GROUP } from './helpers/config';
|
||
import { JmapClient } from './helpers/jmap';
|
||
import {
|
||
login,
|
||
forceSync,
|
||
openComposer,
|
||
composerFromOptions,
|
||
selectComposerFrom,
|
||
selectedComposerFrom,
|
||
} from './helpers/app';
|
||
|
||
/**
|
||
* Issue #569 — the composer's "From" dropdown should include identities from
|
||
* shared/group accounts, not only the logged-in (connected) accounts.
|
||
*
|
||
* Scenario under test (the one expected to already work): a Stalwart *group*
|
||
* mailbox `team@example.org` is provisioned and `carol` is made a member of it
|
||
* *before her first login* (integration/stalwart/plan-accounts.ndjson.tpl +
|
||
* entrypoint.sh). As a member she gets the group's shared folders (shown under
|
||
* "Shared") and — per Stalwart — a `team@` send-as identity (Stalwart returns
|
||
* it among the member's own account identities). The composer should therefore
|
||
* offer `team@example.org` as a sender alongside her own address.
|
||
*/
|
||
const member = ACCOUNTS[GROUP.team.memberOf];
|
||
const { team } = GROUP;
|
||
|
||
test.describe('Composer From: shared/group identities (issue #569)', () => {
|
||
test('the pre-provisioned group account is reachable in the member’s JMAP session', async () => {
|
||
// Server-side guard for the UI expectation below: if this fails, the
|
||
// bootstrap group provisioning is broken (not the app). The member must see
|
||
// the group account in her session, and it must expose a team@ identity she
|
||
// can send as.
|
||
const memberClient = await JmapClient.connect(member.email, member.password);
|
||
expect(memberClient.sharedAccountNames()).toContain(team.email);
|
||
|
||
const groupAccountId = Object.entries(memberClient.accounts).find(
|
||
([, name]) => name === team.email,
|
||
)?.[0];
|
||
expect(groupAccountId).toBeTruthy();
|
||
|
||
const res = await memberClient.request([
|
||
['Identity/get', { accountId: groupAccountId! }, '0'],
|
||
]);
|
||
const groupIdentityEmails = (res.methodResponses[0][1].list as { email: string }[]).map(
|
||
(i) => i.email,
|
||
);
|
||
expect(groupIdentityEmails).toContain(team.email);
|
||
});
|
||
|
||
test('the composer From selector offers and can select the group address', async ({ page }) => {
|
||
await login(page, member);
|
||
// Shared accounts/identities are discovered from the JMAP session; give the
|
||
// client a beat to settle them after the first render.
|
||
await forceSync(page);
|
||
|
||
await openComposer(page);
|
||
|
||
// The group address the member can send as should be one of the From
|
||
// choices. If #569 were unaddressed the control would collapse to her own
|
||
// address only and this poll would time out — which is the point: it pins
|
||
// the expected behaviour.
|
||
await expect
|
||
.poll(async () => (await composerFromOptions(page)).join(' | '), { timeout: 15000 })
|
||
.toContain(team.email);
|
||
|
||
// Pick the group address as the sender and confirm it becomes the selected
|
||
// From identity (not just a listed option).
|
||
await selectComposerFrom(page, team.email);
|
||
await expect.poll(() => selectedComposerFrom(page), { timeout: 5000 }).toContain(team.email);
|
||
|
||
// Hold on the composer so the final video frames clearly show the group
|
||
// address selected in the From field.
|
||
await page.waitForTimeout(2000);
|
||
});
|
||
});
|