aboutsummaryrefslogtreecommitdiffstats
path: root/test/playwright/tests/config.spec.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'test/playwright/tests/config.spec.mjs')
-rw-r--r--test/playwright/tests/config.spec.mjs99
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();
+});