feat(ui): add automation settings and safe AI review presentation
This commit is contained in:
@@ -319,12 +319,31 @@ test('[PRES-S03] Rules draft updates do not refetch an unrelated notification pr
|
||||
});
|
||||
|
||||
function preferenceCopy(key: TranslationKey) { return translations[document.documentElement.lang === 'nb-NO' ? 'nb' : 'en'][key]; }
|
||||
test.each(['en', 'nb'] as const)('%s Automation reuses the saved notification preference and explicit save', async language => {
|
||||
localStorage.setItem('uiLanguage', language); renderView();
|
||||
fireEvent.click(screen.getByRole('tab', { name: preferenceCopy('settingsTabAutomation') }));
|
||||
const panel = within(screen.getByRole('tabpanel', { name: preferenceCopy('settingsTabAutomation') }));
|
||||
const toggle = await panel.findByRole('switch', { name: preferenceCopy('settingsNotificationsFollowUpReminders') });
|
||||
expect(toggle).toBeChecked(); fireEvent.click(toggle); expect(mockedApi.put).not.toHaveBeenCalled();
|
||||
fireEvent.click(screen.getByRole('tab', { name: preferenceCopy('settingsTabNotifications') }));
|
||||
expect(await notificationPanel().findByRole('switch', { name: preferenceCopy('settingsNotificationsFollowUpReminders') })).not.toBeChecked();
|
||||
fireEvent.click(notificationPanel().getByRole('button', { name: preferenceCopy('settingsNotificationsSave') }));
|
||||
await waitFor(() => expect(mockedApi.put).toHaveBeenCalledWith('/notification-settings', { emailFollowUpRemindersEnabled: false }));
|
||||
});
|
||||
|
||||
test('Automation AI entry moves focus into existing settings without an AI request', async () => {
|
||||
renderView(); fireEvent.click(screen.getByRole('tab', { name: preferenceCopy('settingsTabAutomation') }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: preferenceCopy('settingsAutomationAi') }));
|
||||
await waitFor(() => expect(document.getElementById('settings-ai-controls')).toHaveFocus());
|
||||
expect(mockedApi.post).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
function notificationPanel() { return within(screen.getByRole('tabpanel', { name: preferenceCopy('settingsTabNotifications') })); }
|
||||
function notificationReads() { return mockedApi.get.mock.calls.filter(([url]) => url === '/notification-settings'); }
|
||||
function notificationWrites() { return mockedApi.put.mock.calls.filter(([url]) => url === '/notification-settings'); }
|
||||
async function openNotifications() {
|
||||
fireEvent.click(screen.getByRole('tab', { name: preferenceCopy('settingsTabNotifications') }));
|
||||
return notificationPanel().findByRole('checkbox', { name: preferenceCopy('settingsNotificationsFollowUpReminders') });
|
||||
return notificationPanel().findByRole('switch', { name: preferenceCopy('settingsNotificationsFollowUpReminders') });
|
||||
}
|
||||
async function preferenceLanguage(language: 'en' | 'nb') {
|
||||
await act(async () => { window.dispatchEvent(new StorageEvent('storage', { key: 'uiLanguage', newValue: language })); });
|
||||
@@ -345,7 +364,7 @@ test('[P7-09 preferences] initial notification failure offers a single GET Retry
|
||||
act(() => { retry.focus(); fireEvent.click(retry); fireEvent.click(retry); });
|
||||
expect(notificationReads()).toHaveLength(2); expect(mockedApi.put).not.toHaveBeenCalled();
|
||||
await act(async () => pending.resolve({ data: { emailFollowUpRemindersEnabled: false } }));
|
||||
expect(await notificationPanel().findByRole('checkbox', { name: translations.en.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(await notificationPanel().findByRole('switch', { name: translations.en.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(notificationPanel().queryByRole('button', { name: 'Retry' })).not.toBeInTheDocument();
|
||||
expect(notificationPanel().getByRole('group', { name: translations.en.settingsNotificationsTitle })).toHaveFocus();
|
||||
expect(notificationReads()).toHaveLength(2); expect(mockedApi.put).not.toHaveBeenCalled();
|
||||
@@ -359,7 +378,7 @@ test('[P7-09 preferences] notification drafts survive internal sections and loca
|
||||
const retained = await openNotifications();
|
||||
expect(retained).not.toBeChecked(); expect(notificationReads()).toHaveLength(reads);
|
||||
expect(notificationPanel().getByRole('status')).toHaveTextContent(translations.nb.settingsNotificationsDraftScope);
|
||||
await preferenceLanguage('en'); expect(notificationPanel().getByRole('checkbox', { name: translations.en.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
await preferenceLanguage('en'); expect(notificationPanel().getByRole('switch', { name: translations.en.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(notificationReads()).toHaveLength(reads); expect(mockedApi.put).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -375,7 +394,7 @@ test('[P7-09 preferences] one held notification save acknowledges its snapshot a
|
||||
expect(await openNotifications()).toBeChecked();
|
||||
expect(notificationPanel().getByRole('status')).toHaveTextContent(translations.en.assetsUnsavedChanges);
|
||||
fireEvent.click(notificationPanel().getByRole('button', { name: translations.en.assetsDiscardChanges }));
|
||||
expect(notificationPanel().getByRole('checkbox', { name: translations.en.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(notificationPanel().getByRole('switch', { name: translations.en.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(notificationPanel().queryByText(translations.en.settingsNotificationsDraftScope)).not.toBeInTheDocument();
|
||||
expect(notificationReads()).toHaveLength(1); expect(notificationWrites()).toHaveLength(1);
|
||||
});
|
||||
@@ -387,7 +406,7 @@ test('[P7-09 preferences] failed notification save keeps its current-locale draf
|
||||
expect(await notificationPanel().findByRole('alert')).toHaveTextContent(translations.en.settingsNotificationsSaveFailed);
|
||||
const reads = notificationReads().length; await preferenceLanguage('nb');
|
||||
expect(notificationPanel().getByRole('alert')).toHaveTextContent(translations.nb.settingsNotificationsSaveFailed);
|
||||
expect(notificationPanel().getByRole('checkbox', { name: translations.nb.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(notificationPanel().getByRole('switch', { name: translations.nb.settingsNotificationsFollowUpReminders })).not.toBeChecked();
|
||||
expect(notificationPanel().queryByRole('button', { name: translations.nb.retry })).not.toBeInTheDocument();
|
||||
fireEvent.click(notificationPanel().getByRole('button', { name: translations.nb.settingsNotificationsSave }));
|
||||
await waitFor(() => expect(notificationPanel().queryByRole('alert')).not.toBeInTheDocument());
|
||||
@@ -403,7 +422,7 @@ test('[P7-09 preferences] discarding a notification draft leaves the independent
|
||||
renderView(); fireEvent.change(await openRules(), { target: { value: '5' } });
|
||||
fireEvent.click(await openNotifications());
|
||||
fireEvent.click(notificationPanel().getByRole('button', { name: translations.en.assetsDiscardChanges }));
|
||||
expect(notificationPanel().getByRole('checkbox', { name: translations.en.settingsNotificationsFollowUpReminders })).toBeChecked();
|
||||
expect(notificationPanel().getByRole('switch', { name: translations.en.settingsNotificationsFollowUpReminders })).toBeChecked();
|
||||
expect(notificationPanel().queryByText(translations.en.settingsNotificationsDraftScope)).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Follow-ups' }));
|
||||
expect(screen.getByLabelText('Applied: follow-up days')).toHaveValue(5);
|
||||
|
||||
Reference in New Issue
Block a user