Cover bootstrap button state in WebGUI tests
This commit is contained in:
parent
6b2049ccf7
commit
a115d2a012
1 changed files with 117 additions and 57 deletions
|
|
@ -1,114 +1,174 @@
|
||||||
const { test, expect } = require('@playwright/test');
|
const { test, expect } = require("@playwright/test");
|
||||||
|
|
||||||
const username = process.env.OPNSENSE_UI_USERNAME;
|
const username = process.env.OPNSENSE_UI_USERNAME;
|
||||||
const password = process.env.OPNSENSE_UI_PASSWORD;
|
const password = process.env.OPNSENSE_UI_PASSWORD;
|
||||||
|
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
throw new Error('Set OPNSENSE_UI_USERNAME and OPNSENSE_UI_PASSWORD for the disposable OPNsense deployment.');
|
throw new Error(
|
||||||
|
"Set OPNSENSE_UI_USERNAME and OPNSENSE_UI_PASSWORD for the disposable OPNsense deployment.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.OPNSENSE_UI_TEST_ALLOW_MUTATION !== '1') {
|
if (process.env.OPNSENSE_UI_TEST_ALLOW_MUTATION !== "1") {
|
||||||
throw new Error('Set OPNSENSE_UI_TEST_ALLOW_MUTATION=1 to allow enrollment changes in the disposable deployment.');
|
throw new Error(
|
||||||
|
"Set OPNSENSE_UI_TEST_ALLOW_MUTATION=1 to allow enrollment changes in the disposable deployment.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test('renders and preserves NordVPN enrollment controls', async ({ page }) => {
|
test("renders and preserves NordVPN enrollment controls", async ({ page }) => {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
page.on('console', (message) => {
|
page.on("console", (message) => {
|
||||||
if (message.type() === 'error') errors.push(message.text());
|
if (message.type() === "error") errors.push(message.text());
|
||||||
});
|
});
|
||||||
page.on('pageerror', (error) => errors.push(error.stack || error.message));
|
page.on("pageerror", (error) => errors.push(error.stack || error.message));
|
||||||
page.on('response', (response) => {
|
page.on("response", (response) => {
|
||||||
if (response.status() >= 400) errors.push(`${response.status()} ${response.url()}`);
|
if (response.status() >= 400)
|
||||||
|
errors.push(`${response.status()} ${response.url()}`);
|
||||||
});
|
});
|
||||||
await page.route('**/api/nordvpn/service/countries', async (route) => {
|
await page.route("**/api/nordvpn/service/countries", async (route) => {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
contentType: 'application/json',
|
contentType: "application/json",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
status: 'ok',
|
status: "ok",
|
||||||
countries: [
|
countries: [
|
||||||
{ code: 'XA', name: 'Synthetic A' },
|
{ code: "XA", name: "Synthetic A" },
|
||||||
{ code: 'XB', name: 'Synthetic B' },
|
{ code: "XB", name: "Synthetic B" },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
let startBootstrap;
|
||||||
|
const bootstrapStarted = new Promise((resolve) => {
|
||||||
|
startBootstrap = resolve;
|
||||||
|
});
|
||||||
|
let finishBootstrap;
|
||||||
|
await page.route("**/api/nordvpn/service/bootstrap", async (route) => {
|
||||||
|
startBootstrap();
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
finishBootstrap = resolve;
|
||||||
|
});
|
||||||
|
await route.fulfill({
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify({ status: "ok", tunnel: {} }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await page.goto('/');
|
await page.goto("/");
|
||||||
await page.locator('#usernamefld').fill(username);
|
await page.locator("#usernamefld").fill(username);
|
||||||
await page.locator('#passwordfld').fill(password);
|
await page.locator("#passwordfld").fill(password);
|
||||||
await page.getByRole('button', { name: 'Login' }).click();
|
await page.getByRole("button", { name: "Login" }).click();
|
||||||
await page.goto('/ui/nordvpn');
|
await page.goto("/ui/nordvpn");
|
||||||
await expect(page.getByRole('heading', { name: 'NordVPN egress enrollment' })).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("heading", { name: "NordVPN egress enrollment" }),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
const accessToken = page.locator("#accessToken");
|
||||||
|
const bootstrap = page.getByRole("button", { name: "Bootstrap NordLynx" });
|
||||||
|
await accessToken.fill("synthetic-token");
|
||||||
|
await bootstrap.click();
|
||||||
|
await bootstrapStarted;
|
||||||
|
await expect(accessToken).toHaveValue("");
|
||||||
|
await expect(bootstrap).toBeDisabled();
|
||||||
|
finishBootstrap();
|
||||||
|
await expect(bootstrap).toBeEnabled();
|
||||||
|
|
||||||
const countries = page.locator('[id="settings.general.countries"]');
|
const countries = page.locator('[id="settings.general.countries"]');
|
||||||
await expect(countries.locator('option[value="XA"]')).toHaveText('Synthetic A');
|
await expect(countries.locator('option[value="XA"]')).toHaveText(
|
||||||
await expect(countries.locator('option[value="XB"]')).toHaveText('Synthetic B');
|
"Synthetic A",
|
||||||
await expect(countries.locator('xpath=..').locator('button.dropdown-toggle')).toBeVisible();
|
);
|
||||||
|
await expect(countries.locator('option[value="XB"]')).toHaveText(
|
||||||
|
"Synthetic B",
|
||||||
|
);
|
||||||
|
await expect(
|
||||||
|
countries.locator("xpath=..").locator("button.dropdown-toggle"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
const failurePolicy = page.locator('[id="settings.general.failure_policy"]');
|
const failurePolicy = page.locator('[id="settings.general.failure_policy"]');
|
||||||
await expect(failurePolicy.locator('option[value="fail_closed"]')).toHaveText('Block traffic');
|
await expect(failurePolicy.locator('option[value="fail_closed"]')).toHaveText(
|
||||||
await expect(failurePolicy.locator('option[value="fail_open"]')).toHaveText('Use direct egress');
|
"Block traffic",
|
||||||
|
);
|
||||||
|
await expect(failurePolicy.locator('option[value="fail_open"]')).toHaveText(
|
||||||
|
"Use direct egress",
|
||||||
|
);
|
||||||
|
|
||||||
const grid = page.getByRole('grid');
|
const grid = page.getByRole("grid");
|
||||||
const testRows = grid.getByRole('row').filter({ hasText: 'UI_TEST_NETWORK' });
|
const testRows = grid.getByRole("row").filter({ hasText: "UI_TEST_NETWORK" });
|
||||||
while (await testRows.count()) {
|
while (await testRows.count()) {
|
||||||
const before = await testRows.count();
|
const before = await testRows.count();
|
||||||
await testRows.first().getByRole('button', { name: 'Delete' }).click();
|
await testRows.first().getByRole("button", { name: "Delete" }).click();
|
||||||
const removal = page.getByRole('dialog', { name: 'Remove' });
|
const removal = page.getByRole("dialog", { name: "Remove" });
|
||||||
await removal.getByRole('button', { name: 'Yes' }).click();
|
await removal.getByRole("button", { name: "Yes" }).click();
|
||||||
await expect(testRows).toHaveCount(before - 1);
|
await expect(testRows).toHaveCount(before - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Add', exact: true }).click();
|
await page.getByRole("button", { name: "Add", exact: true }).click();
|
||||||
const dialog = page.locator('.modal:visible');
|
const dialog = page.locator(".modal:visible");
|
||||||
await expect(dialog).toBeVisible();
|
await expect(dialog).toBeVisible();
|
||||||
await dialog.locator('[id="enrollment.interfaces"]').selectOption('lan');
|
await dialog.locator('[id="enrollment.interfaces"]').selectOption("lan");
|
||||||
|
|
||||||
const source = dialog.locator('select[for="enrollment.source"]');
|
const source = dialog.locator('select[for="enrollment.source"]');
|
||||||
const destination = dialog.locator('select[for="enrollment.destination"]');
|
const destination = dialog.locator('select[for="enrollment.destination"]');
|
||||||
await expect(source).toBeVisible();
|
await expect(source).toBeVisible();
|
||||||
await expect(destination).toBeVisible();
|
await expect(destination).toBeVisible();
|
||||||
await expect(source.locator('option[value="UI_TEST_NETWORK"]')).toHaveText('UI_TEST_NETWORK');
|
await expect(source.locator('option[value="UI_TEST_NETWORK"]')).toHaveText(
|
||||||
|
"UI_TEST_NETWORK",
|
||||||
|
);
|
||||||
|
|
||||||
const destinationPicker = destination.locator('xpath=..');
|
const destinationPicker = destination.locator("xpath=..");
|
||||||
const destinationToggle = destinationPicker.locator('button.dropdown-toggle');
|
const destinationToggle = destinationPicker.locator("button.dropdown-toggle");
|
||||||
await destinationToggle.click();
|
await destinationToggle.click();
|
||||||
const destinationMenu = destinationPicker.locator('.dropdown-menu.open').first();
|
const destinationMenu = destinationPicker
|
||||||
|
.locator(".dropdown-menu.open")
|
||||||
|
.first();
|
||||||
await expect(destinationMenu).toBeVisible();
|
await expect(destinationMenu).toBeVisible();
|
||||||
const menuBox = await destinationMenu.boundingBox();
|
const menuBox = await destinationMenu.boundingBox();
|
||||||
const footerBox = await dialog.locator('.modal-footer').boundingBox();
|
const footerBox = await dialog.locator(".modal-footer").boundingBox();
|
||||||
expect(menuBox.y + menuBox.height).toBeLessThanOrEqual(footerBox.y);
|
expect(menuBox.y + menuBox.height).toBeLessThanOrEqual(footerBox.y);
|
||||||
await destinationToggle.click();
|
await destinationToggle.click();
|
||||||
|
|
||||||
await source.selectOption('UI_TEST_NETWORK');
|
await source.selectOption("UI_TEST_NETWORK");
|
||||||
await destination.selectOption('any');
|
await destination.selectOption("any");
|
||||||
await dialog.getByRole('button', { name: 'Save', exact: true }).click();
|
await dialog.getByRole("button", { name: "Save", exact: true }).click();
|
||||||
await expect(dialog).toBeHidden();
|
await expect(dialog).toBeHidden();
|
||||||
await page.reload();
|
await page.reload();
|
||||||
await expect(page.getByRole('heading', { name: 'NordVPN egress enrollment' })).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("heading", { name: "NordVPN egress enrollment" }),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
const row = page.getByRole('row').filter({ hasText: 'LAN' }).filter({ hasText: 'UI_TEST_NETWORK' }).first();
|
const row = page
|
||||||
|
.getByRole("row")
|
||||||
|
.filter({ hasText: "LAN" })
|
||||||
|
.filter({ hasText: "UI_TEST_NETWORK" })
|
||||||
|
.first();
|
||||||
await expect(row).toBeVisible();
|
await expect(row).toBeVisible();
|
||||||
|
|
||||||
await row.getByRole('button', { name: 'Edit' }).click();
|
await row.getByRole("button", { name: "Edit" }).click();
|
||||||
await expect(dialog).toBeVisible();
|
await expect(dialog).toBeVisible();
|
||||||
await expect(dialog.locator('select[for="enrollment.source"]')).toHaveValues(['UI_TEST_NETWORK']);
|
await expect(dialog.locator('select[for="enrollment.source"]')).toHaveValues([
|
||||||
await expect(dialog.locator('select[for="enrollment.destination"]')).toHaveValues(['any']);
|
"UI_TEST_NETWORK",
|
||||||
await dialog.getByRole('button', { name: 'Close' }).click();
|
]);
|
||||||
|
await expect(
|
||||||
|
dialog.locator('select[for="enrollment.destination"]'),
|
||||||
|
).toHaveValues(["any"]);
|
||||||
|
await dialog.getByRole("button", { name: "Close" }).click();
|
||||||
await expect(dialog).toBeHidden();
|
await expect(dialog).toBeHidden();
|
||||||
|
|
||||||
await row.getByRole('button', { name: 'Clone' }).click();
|
await row.getByRole("button", { name: "Clone" }).click();
|
||||||
await expect(dialog).toBeVisible();
|
await expect(dialog).toBeVisible();
|
||||||
await expect(dialog.locator('select[for="enrollment.source"]')).toHaveValues(['UI_TEST_NETWORK']);
|
await expect(dialog.locator('select[for="enrollment.source"]')).toHaveValues([
|
||||||
await expect(dialog.locator('select[for="enrollment.destination"]')).toHaveValues(['any']);
|
"UI_TEST_NETWORK",
|
||||||
await dialog.getByRole('button', { name: 'Close' }).click();
|
]);
|
||||||
|
await expect(
|
||||||
|
dialog.locator('select[for="enrollment.destination"]'),
|
||||||
|
).toHaveValues(["any"]);
|
||||||
|
await dialog.getByRole("button", { name: "Close" }).click();
|
||||||
await expect(dialog).toBeHidden();
|
await expect(dialog).toBeHidden();
|
||||||
|
|
||||||
const beforeDelete = await testRows.count();
|
const beforeDelete = await testRows.count();
|
||||||
await row.getByRole('button', { name: 'Delete' }).click();
|
await row.getByRole("button", { name: "Delete" }).click();
|
||||||
const removal = page.getByRole('dialog', { name: 'Remove' });
|
const removal = page.getByRole("dialog", { name: "Remove" });
|
||||||
await expect(removal).toBeVisible();
|
await expect(removal).toBeVisible();
|
||||||
await removal.getByRole('button', { name: 'Yes' }).click();
|
await removal.getByRole("button", { name: "Yes" }).click();
|
||||||
await expect(testRows).toHaveCount(beforeDelete - 1);
|
await expect(testRows).toHaveCount(beforeDelete - 1);
|
||||||
|
|
||||||
expect(errors).toEqual([]);
|
expect(errors).toEqual([]);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue