174 lines
6.8 KiB
TypeScript
174 lines
6.8 KiB
TypeScript
/**
|
|
* System Settings Persistence E2E Tests
|
|
*
|
|
* Verifies that settings survive a page reload (persisted to backend, not just React state).
|
|
* Pattern: record → change → reload → assert persisted → restore.
|
|
* All operations via UI — zero invokeBridge, zero mock.
|
|
*/
|
|
|
|
import { test, expect } from '../../../fixtures';
|
|
import { goToSettings, waitForSettle, waitForClassChange } from '../../../helpers/navigation';
|
|
import { ARCO_SWITCH } from '../../../helpers/selectors';
|
|
|
|
async function reloadAndGoToSystem(page: import('@playwright/test').Page) {
|
|
await page.reload();
|
|
await goToSettings(page, 'system');
|
|
await waitForSettle(page);
|
|
}
|
|
|
|
test.describe('System Settings Persistence', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await goToSettings(page, 'system');
|
|
await waitForSettle(page);
|
|
});
|
|
|
|
// TC-PERSIST-01: Language switch persists across reload
|
|
test('TC-PERSIST-01: language selection persists after reload', async ({ page }) => {
|
|
const selectTrigger = page.locator('.aion-select .arco-select-view').first();
|
|
await expect(selectTrigger).toBeVisible();
|
|
const originalLang = await selectTrigger.textContent();
|
|
|
|
await selectTrigger.click();
|
|
const englishOption = page.locator('.arco-select-option:has-text("English")');
|
|
await expect(englishOption).toBeVisible();
|
|
await englishOption.click();
|
|
await page.waitForFunction(() => document.body.textContent?.includes('Language'), { timeout: 15_000 });
|
|
expect(await selectTrigger.textContent()).toContain('English');
|
|
|
|
await reloadAndGoToSystem(page);
|
|
|
|
const reloadedSelect = page.locator('.aion-select .arco-select-view').first();
|
|
await expect(reloadedSelect).toBeVisible();
|
|
expect(await reloadedSelect.textContent()).toContain('English');
|
|
expect(await page.locator('body').textContent()).toContain('Language');
|
|
|
|
// Restore
|
|
await reloadedSelect.click();
|
|
const restoreOption = page.locator(`.arco-select-option:has-text("${originalLang?.trim() || '简体中文'}")`);
|
|
await expect(restoreOption).toBeVisible();
|
|
await restoreOption.click();
|
|
await waitForSettle(page);
|
|
});
|
|
|
|
// TC-PERSIST-02: closeToTray switch persists across reload
|
|
// Known issue: systemSettings.setCloseToTray writes via HTTP but reload reads from
|
|
// configService cache which may not reflect the update. Skipped until cache consistency is fixed.
|
|
test.skip('TC-PERSIST-02: closeToTray toggle persists after reload', async ({ page }) => {
|
|
const closeToTraySwitch = page.locator(`.divide-y ${ARCO_SWITCH}`).nth(1);
|
|
await expect(closeToTraySwitch).toBeVisible();
|
|
const wasChecked = await closeToTraySwitch.evaluate((el) => el.classList.contains('arco-switch-checked'));
|
|
|
|
await closeToTraySwitch.click();
|
|
await waitForClassChange(closeToTraySwitch);
|
|
expect(await closeToTraySwitch.evaluate((el) => el.classList.contains('arco-switch-checked'))).toBe(!wasChecked);
|
|
|
|
await reloadAndGoToSystem(page);
|
|
|
|
const reloadedSwitch = page.locator(`.divide-y ${ARCO_SWITCH}`).nth(1);
|
|
await expect(reloadedSwitch).toBeVisible();
|
|
await page.waitForFunction(
|
|
(expected: boolean) => {
|
|
const el = document.querySelectorAll('.divide-y .arco-switch')[1];
|
|
return el?.classList.contains('arco-switch-checked') === expected;
|
|
},
|
|
!wasChecked,
|
|
{ timeout: 15_000 }
|
|
);
|
|
expect(await reloadedSwitch.evaluate((el) => el.classList.contains('arco-switch-checked'))).toBe(!wasChecked);
|
|
|
|
// Restore
|
|
await reloadedSwitch.click();
|
|
await waitForClassChange(reloadedSwitch);
|
|
});
|
|
|
|
// TC-PERSIST-03: promptTimeout InputNumber persists across reload
|
|
test('TC-PERSIST-03: promptTimeout value persists after reload', async ({ page }) => {
|
|
const wrapper = page
|
|
.locator('.arco-input-number')
|
|
.filter({ has: page.locator('[class*="suffix"]:has-text("s")') })
|
|
.first();
|
|
await expect(wrapper).toBeVisible({ timeout: 15_000 });
|
|
|
|
const input = wrapper.locator('input');
|
|
const originalValue = (await input.inputValue()).trim();
|
|
|
|
await input.click();
|
|
await page.keyboard.press('Meta+a');
|
|
await input.fill('600');
|
|
await input.blur();
|
|
await waitForSettle(page, 500);
|
|
expect(Number((await input.inputValue()).trim())).toBe(600);
|
|
|
|
await reloadAndGoToSystem(page);
|
|
|
|
const reloadedWrapper = page
|
|
.locator('.arco-input-number')
|
|
.filter({ has: page.locator('[class*="suffix"]:has-text("s")') })
|
|
.first();
|
|
await expect(reloadedWrapper).toBeVisible({ timeout: 15_000 });
|
|
const reloadedInput = reloadedWrapper.locator('input');
|
|
|
|
// Wait for the value to be hydrated from backend
|
|
await page
|
|
.waitForFunction(
|
|
() => {
|
|
const inputs = document.querySelectorAll<HTMLInputElement>('.arco-input-number input');
|
|
for (const el of inputs) {
|
|
if (el.value.trim() === '600') return true;
|
|
}
|
|
return false;
|
|
},
|
|
{ timeout: 15_000 }
|
|
)
|
|
.catch(() => {});
|
|
|
|
expect(Number((await reloadedInput.inputValue()).trim())).toBe(600);
|
|
|
|
// Restore
|
|
await reloadedInput.click();
|
|
await page.keyboard.press('Meta+a');
|
|
await reloadedInput.fill(originalValue || '300');
|
|
await reloadedInput.blur();
|
|
await waitForSettle(page, 500);
|
|
});
|
|
|
|
// Known issue: same configService cache consistency problem as TC-PERSIST-02.
|
|
test.skip('TC-PERSIST-04: notification toggle persists after reload', async ({ page }) => {
|
|
const collapseHeader = page.locator('.arco-collapse-item-header');
|
|
await expect(collapseHeader).toBeVisible();
|
|
const notifSwitch = collapseHeader.locator(ARCO_SWITCH);
|
|
await expect(notifSwitch).toBeVisible();
|
|
const wasChecked = await notifSwitch.evaluate((el) => el.classList.contains('arco-switch-checked'));
|
|
|
|
await notifSwitch.click();
|
|
await waitForClassChange(notifSwitch);
|
|
expect(await notifSwitch.evaluate((el) => el.classList.contains('arco-switch-checked'))).toBe(!wasChecked);
|
|
|
|
await reloadAndGoToSystem(page);
|
|
|
|
const reloadedNotifSwitch = page.locator('.arco-collapse-item-header').locator(ARCO_SWITCH);
|
|
await expect(reloadedNotifSwitch).toBeVisible();
|
|
await page.waitForFunction(
|
|
(expected: boolean) => {
|
|
const el = document.querySelector('.arco-collapse-item-header .arco-switch');
|
|
return el?.classList.contains('arco-switch-checked') === expected;
|
|
},
|
|
!wasChecked,
|
|
{ timeout: 15_000 }
|
|
);
|
|
expect(await reloadedNotifSwitch.evaluate((el) => el.classList.contains('arco-switch-checked'))).toBe(!wasChecked);
|
|
|
|
// Verify Collapse expand/collapse matches the switch state
|
|
const collapseContent = page.locator('.arco-collapse-item-content');
|
|
if (!wasChecked) {
|
|
await expect(collapseContent).toBeVisible();
|
|
} else {
|
|
await expect(collapseContent).not.toBeVisible();
|
|
}
|
|
|
|
// Restore
|
|
await reloadedNotifSwitch.click();
|
|
await waitForClassChange(reloadedNotifSwitch);
|
|
});
|
|
});
|