Feat/unified mailbox account scope Rework the sidebar "All accounts" into an account-bounded "Unified Mailbox" by default, with cross-account merging as an opt-in (admin-gated) sub-option. The standalone per-account "All Mail" virtual folder is folded into the unified All mail / Unread / Starred entries. Conflict resolution notes: - stores/settings-store.ts: both main and this branch independently added a per-account default-identity (#507) migration at different versions (main v6, branch v7). Merged migration is version 7 using the refactored migrateSettings function; the unified-mailbox rework is guarded at `version < 7` so users who stopped at main's interim v6 identity bump still receive it, while the #507 identity-map coercion stays at `version < 6` so their populated map is kept. - stores/auth-store.ts: kept main's applyPreferredIdentity (superset with the pre-#507 legacy migration). - stores/email-store.ts: removed the ALL_MAIL_MAILBOX_ID paths (folded into the unified views) while preserving main's plugin hooks (onSearchResults / onEmailsFetched); adopted advancedSearchCrossViewEmails for advanced cross-view search. - components/settings/layout-settings.tsx: kept main's faviconUnreadBadge setting alongside the new unifiedCrossAccount toggle. - integration/: union-merged the two independently-authored suites - branch suite is authoritative (matches new behavior) with main's shared-identity (#569) group infrastructure preserved. - components/email/email-composer.tsx: dropped a duplicate data-testid attribute introduced by the auto-merge.
82 lines
3.4 KiB
TypeScript
82 lines
3.4 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { useSettingsStore, migrateSettings } from '../settings-store';
|
|
|
|
describe('settings-store per-account preferredIdentityIds (issue #507)', () => {
|
|
beforeEach(() => {
|
|
useSettingsStore.setState({ preferredIdentityIds: {} });
|
|
});
|
|
|
|
it('defaults to an empty record (no account has a synced default)', () => {
|
|
expect(useSettingsStore.getState().preferredIdentityIds).toEqual({});
|
|
});
|
|
|
|
it('keeps each account default independent', () => {
|
|
useSettingsStore.setState({
|
|
preferredIdentityIds: { 'acct-1': 'b', 'acct-2': 'c' },
|
|
});
|
|
const map = useSettingsStore.getState().preferredIdentityIds;
|
|
expect(map['acct-1']).toBe('b');
|
|
expect(map['acct-2']).toBe('c');
|
|
expect(map['acct-3']).toBeUndefined();
|
|
});
|
|
|
|
it('round-trips through export -> import so the choice survives clearing site data', () => {
|
|
useSettingsStore.setState({ preferredIdentityIds: { 'acct-1': 'b' } });
|
|
const json = useSettingsStore.getState().exportSettings();
|
|
// Appears in exported JSON (issue #507 acceptance criterion).
|
|
expect(JSON.parse(json).preferredIdentityIds).toEqual({ 'acct-1': 'b' });
|
|
|
|
// Simulate a fresh browser: clear, then import the exported settings.
|
|
useSettingsStore.setState({ preferredIdentityIds: {} });
|
|
expect(useSettingsStore.getState().importSettings(json)).toBe(true);
|
|
expect(useSettingsStore.getState().preferredIdentityIds).toEqual({ 'acct-1': 'b' });
|
|
});
|
|
|
|
describe('importSettings non-record guard', () => {
|
|
it('ignores a legacy array shape', () => {
|
|
useSettingsStore.setState({ preferredIdentityIds: { 'acct-1': 'b' } });
|
|
const ok = useSettingsStore.getState().importSettings(
|
|
JSON.stringify({ preferredIdentityIds: ['b'] }),
|
|
);
|
|
expect(ok).toBe(true);
|
|
expect(useSettingsStore.getState().preferredIdentityIds).toEqual({ 'acct-1': 'b' });
|
|
});
|
|
|
|
it('ignores a null value', () => {
|
|
useSettingsStore.setState({ preferredIdentityIds: { 'acct-1': 'b' } });
|
|
useSettingsStore.getState().importSettings(JSON.stringify({ preferredIdentityIds: null }));
|
|
expect(useSettingsStore.getState().preferredIdentityIds).toEqual({ 'acct-1': 'b' });
|
|
});
|
|
|
|
it('accepts a proper per-account record', () => {
|
|
useSettingsStore.getState().importSettings(
|
|
JSON.stringify({ preferredIdentityIds: { 'acct-9': 'a' } }),
|
|
);
|
|
expect(useSettingsStore.getState().preferredIdentityIds).toEqual({ 'acct-9': 'a' });
|
|
});
|
|
});
|
|
|
|
describe('migrateSettings identity map', () => {
|
|
it('adds an empty preferredIdentityIds map for pre-v6 users', () => {
|
|
const out = migrateSettings({ allMailFolderIds: {} }, 6) as unknown as Record<string, unknown>;
|
|
expect(out.preferredIdentityIds).toEqual({});
|
|
});
|
|
|
|
it('coerces a non-record preferredIdentityIds to an empty map', () => {
|
|
const out = migrateSettings(
|
|
{ allMailFolderIds: {}, preferredIdentityIds: ['b'] },
|
|
7,
|
|
) as unknown as Record<string, unknown>;
|
|
expect(out.preferredIdentityIds).toEqual({});
|
|
});
|
|
|
|
it('preserves a valid per-account map across migration', () => {
|
|
const out = migrateSettings(
|
|
{ allMailFolderIds: {}, preferredIdentityIds: { 'acct-1': 'b' } },
|
|
7,
|
|
) as unknown as Record<string, unknown>;
|
|
expect(out.preferredIdentityIds).toEqual({ 'acct-1': 'b' });
|
|
});
|
|
});
|
|
});
|