diff options
Diffstat (limited to 'test/playwright/tests/config.spec.mjs')
-rw-r--r-- | test/playwright/tests/config.spec.mjs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/test/playwright/tests/config.spec.mjs b/test/playwright/tests/config.spec.mjs new file mode 100644 index 000000000..3962e7a7b --- /dev/null +++ b/test/playwright/tests/config.spec.mjs @@ -0,0 +1,99 @@ +import {expect, test} from "@playwright/test"; +import {login} from "../helpers/auth.mjs"; + +async function logAlertOnError(page, locator, fn) { + try { + await fn(); + } catch (e) { + const alertText = await locator.textContent(); + // eslint-disable-next-line no-console + console.log("[E2E] Alert error text:", alertText); + throw e; + } +} + +// Helper function for sequentially filling in fields +function fillSequentially(elements, values) { + return elements.reduce((promise, el, i) => promise.then(() => el.fill(values[i])), Promise.resolve()); +} + +test("Config page: always checks order error and valid save for actions", async ({page}, testInfo) => { + const {enablePassword} = testInfo.project.use.rspamdPasswords; + await login(page, enablePassword); + + await page.locator("#configuration_nav").click(); + await expect(page.locator("#actionsFormField")).toBeVisible({timeout: 10000}); + + function getInputs() { return page.locator("#actionsFormField input[data-id='action']"); } + const alert = page.locator(".alert-error, .alert-modal.alert-error"); + + const inputs = getInputs(); + const count = await inputs.count(); + expect(count).toBeGreaterThan(0); + await Promise.all( + Array.from({length: count}, (_, i) => expect(inputs.nth(i)).toBeVisible()) + ); + + // Save the original values + const values = await Promise.all(Array.from({length: count}, (_, i) => inputs.nth(i).inputValue())); + + // Determine only the fields actually available for input (not disabled, not readonly) + const fillableChecks = Array.from({length: count}, (_, i) => (async () => { + const input = inputs.nth(i); + const isDisabled = await input.isDisabled(); + const isReadOnly = await input.evaluate((el) => el.hasAttribute("readonly")); + return !isDisabled && !isReadOnly ? i : null; + })()); + const fillableIndices = (await Promise.all(fillableChecks)).filter((i) => i !== null); + + const fillableInputs = fillableIndices.map((i) => inputs.nth(i)); + + // 1. Correct order: strictly decreasing sequence + const correctOrder = fillableIndices.map((_, idx) => (idx * 10).toString()); + + await fillSequentially(fillableInputs, correctOrder); + + await page.locator("#saveActionsBtn").click(); + + await logAlertOnError(page, alert, async () => { + await expect(alert).not.toBeVisible({timeout: 2000}); + }); + + // Reload the configuration and make sure the new value has been saved + await page.locator("#refresh").click(); + await page.locator("#configuration_nav").click(); + + const reloadedInputs = getInputs(); + const reloadedCount = await reloadedInputs.count(); + + // Recalculate the fillable fields after reload + const reloadedFillableChecks = Array.from({length: reloadedCount}, (_, i) => (async () => { + const input = reloadedInputs.nth(i); + const isDisabled = await input.isDisabled(); + const isReadOnly = await input.evaluate((el) => el.hasAttribute("readonly")); + return !isDisabled && !isReadOnly ? i : null; + })()); + const reloadedFillableIndices = (await Promise.all(reloadedFillableChecks)).filter((i) => i !== null); + const reloadedFillableInputs = reloadedFillableIndices.map((i) => reloadedInputs.nth(i)); + + await Promise.all(reloadedFillableInputs.map((input) => expect(input).toBeVisible())); + + const saved = await Promise.all(reloadedFillableInputs.map((input) => input.inputValue())); + expect(saved).toEqual(correctOrder); + + // 2. Break the order: increasing sequence + const wrongOrder = reloadedFillableIndices.map((_, idx) => ((reloadedFillableIndices.length - idx) * 10).toString()); + + await fillSequentially(reloadedFillableInputs, wrongOrder); + + await page.locator("#saveActionsBtn").click(); + + await expect(alert).toBeVisible({timeout: 10000}); + const alertText = await alert.textContent(); + expect(alertText).toContain("Incorrect order of actions thresholds"); + + // Restore the original values + await fillSequentially(reloadedFillableInputs, values); + + await page.locator("#saveActionsBtn").click(); +}); |