mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-03 08:15:38 +00:00
fix: wait for the settings page before scrolling to a linked section
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// Until the session is up, Settings draws its page skeleton (the one the
|
||||
@@ -23,12 +23,15 @@ vi.mock('@/hooks/use-config', () => ({ useConfig: () => ({ appName: 'Mail', stal
|
||||
vi.mock('@/components/layout/navigation-rail', () => ({ NavigationRail: () => null }));
|
||||
vi.mock('@/components/layout/sidebar-apps-modal', () => ({ SidebarAppsModal: () => null }));
|
||||
vi.mock('@/components/plugins/app-top-banner-slot', () => ({ AppTopBannerSlot: () => null }));
|
||||
vi.mock('@/components/settings/appearance-settings', () => ({ AppearanceSettings: () => <div>appearance pane</div> }));
|
||||
vi.mock('@/components/settings/appearance-settings', () => ({
|
||||
AppearanceSettings: () => <div data-settings-section="theme">appearance pane</div>,
|
||||
}));
|
||||
|
||||
const { SettingsApp } = await import('../settings-app');
|
||||
const { useAuthStore } = await import('@/stores/auth-store');
|
||||
const { usePluginStore } = await import('@/stores/plugin-store');
|
||||
const { useThemeStore } = await import('@/stores/theme-store');
|
||||
const { useSettingsStore } = await import('@/stores/settings-store');
|
||||
const { SETTINGS_NAV_GROUPS } = await import('../settings-tab-icons');
|
||||
const { BOOT_HINTS_KEY } = await import('@/lib/boot-skeleton/keys');
|
||||
const { resetRailHintsMemo } = await import('@/lib/boot-skeleton/hints');
|
||||
@@ -102,3 +105,26 @@ describe('Settings while the session restores', () => {
|
||||
expect(hints?.settings).not.toContain('vacation');
|
||||
});
|
||||
});
|
||||
|
||||
describe('a link to a section while the session restores', () => {
|
||||
it('scrolls once the page is drawn, without switching Advanced on meanwhile', async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
const scroll = vi.fn();
|
||||
Element.prototype.scrollIntoView = scroll;
|
||||
useSettingsStore.setState({ showAdvancedSettings: false });
|
||||
useAuthStore.setState({ isAuthenticated: true, isLoading: true, client: null });
|
||||
render(<SettingsApp linkSegments={['appearance', 'theme']} />);
|
||||
await act(async () => { vi.advanceTimersByTime(3000); });
|
||||
// The skeleton has no sections; nothing to find is not a hidden section.
|
||||
expect(useSettingsStore.getState().showAdvancedSettings).toBe(false);
|
||||
expect(scroll).not.toHaveBeenCalled();
|
||||
|
||||
act(() => { useAuthStore.setState({ isLoading: false, client: fullClient as never }); });
|
||||
await act(async () => { vi.advanceTimersByTime(200); });
|
||||
expect(scroll).toHaveBeenCalled();
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -446,8 +446,12 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
// an advanced section stays hidden until the switch is on, so after a
|
||||
// short wait turn it on rather than give up.
|
||||
const updateSetting = useSettingsStore((s) => s.updateSetting);
|
||||
// The page itself rather than its skeleton (see the gate below).
|
||||
const pageShown = isAuthenticated && !!client;
|
||||
useEffect(() => {
|
||||
if (!pendingSection || pendingSection.tab !== activeTab) return;
|
||||
// The skeleton has no sections: wait until the page is drawn.
|
||||
if (!pageShown) return;
|
||||
if (typeof window === 'undefined') return;
|
||||
let cancelled = false;
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
@@ -468,7 +472,7 @@ export function SettingsApp({ linkSegments: routeSegments }: SettingsAppProps =
|
||||
window.cancelAnimationFrame(raf);
|
||||
if (timer) clearTimeout(timer);
|
||||
};
|
||||
}, [pendingSection, activeTab, updateSetting]);
|
||||
}, [pendingSection, activeTab, updateSetting, pageShown]);
|
||||
|
||||
// Leaving the settings panel drops any shared-account scope so it never
|
||||
// leaks into the next visit or another session.
|
||||
|
||||
Reference in New Issue
Block a user