mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
test(integration): multi-account address-book aggregation across a switch
Companion to the calendar spec for the cross-account id-namespacing fix. Logs in two accounts, enables the Pro shell, and asserts both accounts' address books stay aggregated (same set, no loss/duplication/corruption) after switching the active account. Contacts keep no persisted id-selection, so this verifies the aggregated list stays correct/usable rather than a selection reset. Adds a data-testid on address-book rows (address-book-item + data-book-name/ -account) and openContacts / addressBookRows helpers.
This commit is contained in:
@@ -846,6 +846,9 @@ function AddressBookItem({
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
data-testid="address-book-item"
|
||||
data-book-name={book.name}
|
||||
data-account={book.accountName ?? ''}
|
||||
className={cn(
|
||||
"w-full flex items-center gap-2 ps-5 pe-3 text-sm transition-colors",
|
||||
isActive
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
import { ACCOUNTS } from './helpers/config';
|
||||
import {
|
||||
login,
|
||||
addAccount,
|
||||
enableProInterface,
|
||||
openContacts,
|
||||
addressBookRows,
|
||||
} from './helpers/app';
|
||||
|
||||
/**
|
||||
* Multi-account address-book aggregation across an account switch.
|
||||
*
|
||||
* Companion to the calendar spec for the cross-account id-namespacing fix.
|
||||
* Contacts keep no persisted id-selection (unlike calendars'
|
||||
* selectedCalendarIds), so there is no selection to reset; the observable here
|
||||
* is that the aggregated cross-account address-book list stays correct and
|
||||
* usable after switching the active account (the store now namespaces every
|
||||
* account consistently, so ids no longer flip form on a switch).
|
||||
*/
|
||||
const { alice, bob } = ACCOUNTS;
|
||||
|
||||
const switcher = (page: Page) => page.locator('[data-testid="account-switcher"]').first();
|
||||
|
||||
async function accountId(page: Page, email: string): Promise<string> {
|
||||
await switcher(page).click();
|
||||
const id = await page
|
||||
.locator(`[data-testid="account-option"][data-account-email="${email}"]`)
|
||||
.first()
|
||||
.getAttribute('data-account-id');
|
||||
await page.keyboard.press('Escape');
|
||||
if (!id) throw new Error(`no account id for ${email}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
async function switchTo(page: Page, id: string): Promise<void> {
|
||||
await switcher(page).click();
|
||||
await page.locator(`[data-testid="account-option"][data-account-id="${id}"]`).first().click({ force: true });
|
||||
await expect
|
||||
.poll(async () => switcher(page).getAttribute('data-active-account-id'), { timeout: 30000 })
|
||||
.toBe(id);
|
||||
}
|
||||
|
||||
test.describe('Multi-account contacts', () => {
|
||||
test('address books from both accounts stay aggregated across a switch', async ({ page }) => {
|
||||
await login(page, alice);
|
||||
await addAccount(page, bob);
|
||||
const bobId = await accountId(page, bob.email);
|
||||
await enableProInterface(page);
|
||||
|
||||
await openContacts(page);
|
||||
|
||||
// Both accounts' (default) address books aggregate into one list with
|
||||
// distinct names.
|
||||
const before = await addressBookRows(page);
|
||||
expect(before.length).toBeGreaterThanOrEqual(2);
|
||||
const namesBefore = new Set(before.map((b) => b.name));
|
||||
expect(namesBefore.size).toBeGreaterThanOrEqual(2);
|
||||
|
||||
// Switch the active account: the previously-active account's ids flip
|
||||
// raw<->namespaced. The aggregated list must remain the same set (no loss,
|
||||
// no duplication, no corruption from the id-form change).
|
||||
await switchTo(page, bobId);
|
||||
await openContacts(page);
|
||||
|
||||
const after = await addressBookRows(page);
|
||||
expect(after.length).toBe(before.length);
|
||||
expect(new Set(after.map((b) => b.name))).toEqual(namesBefore);
|
||||
});
|
||||
});
|
||||
@@ -428,3 +428,26 @@ export async function enableProInterface(page: Page): Promise<void> {
|
||||
await expect(toggle).toHaveAttribute('aria-checked', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
// --- Contacts / address books (multi-account) ------------------------------
|
||||
|
||||
/** Navigate to contacts via in-app nav and wait for the address-book list. */
|
||||
export async function openContacts(page: Page): Promise<void> {
|
||||
await page.locator('a[href$="/contacts"]').first().click();
|
||||
await page
|
||||
.locator('[data-testid="address-book-item"]')
|
||||
.first()
|
||||
.waitFor({ state: 'visible', timeout: 30000 });
|
||||
}
|
||||
|
||||
/** All sidebar address books as {name, account}. */
|
||||
export async function addressBookRows(
|
||||
page: Page,
|
||||
): Promise<Array<{ name: string; account: string }>> {
|
||||
return page.locator('[data-testid="address-book-item"]').evaluateAll((els) =>
|
||||
els.map((e) => ({
|
||||
name: e.getAttribute('data-book-name') || '',
|
||||
account: e.getAttribute('data-account') || '',
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user