Constrain UI tests to disposable targets
This commit is contained in:
parent
1ef0b80415
commit
7c4f4ffe0d
3 changed files with 18 additions and 9 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
# OPNsense WebGUI integration tests
|
# OPNsense WebGUI integration tests
|
||||||
|
|
||||||
These Playwright tests use a disposable OPNsense deployment. They create and delete NordVPN enrollment records and require `OPNSENSE_UI_TEST_ALLOW_MUTATION=1`.
|
These Playwright tests use a disposable OPNsense deployment. They create and delete only entries containing the synthetic `UI_TEST_NETWORK` alias and require `OPNSENSE_UI_TEST_ALLOW_MUTATION=1`.
|
||||||
|
|
||||||
Start a QEMU fixture after building a package. The launcher needs a compatible OPNsense base image and transfer disk, neither of which is stored in this repository.
|
Start a QEMU fixture after building a package. The launcher needs a compatible OPNsense base image and transfer disk, neither of which is stored in this repository.
|
||||||
|
|
||||||
|
|
@ -22,3 +22,5 @@ sh -c 'cd tests/ui && pnpm install --frozen-lockfile && pnpm test'
|
||||||
```
|
```
|
||||||
|
|
||||||
The suite mocks only the countries API response with synthetic values. It covers populated country options, failure-policy labels, native alias selectors, Add/Edit/Clone state restoration, and the selector menu/footer layout.
|
The suite mocks only the countries API response with synthetic values. It covers populated country options, failure-policy labels, native alias selectors, Add/Edit/Clone state restoration, and the selector menu/footer layout.
|
||||||
|
|
||||||
|
The browser target must be loopback by default. A remote disposable deployment requires `OPNSENSE_UI_TEST_ALLOW_REMOTE=1` and a trusted TLS certificate.
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,20 @@ if (!baseURL) {
|
||||||
throw new Error('Set OPNSENSE_UI_BASE_URL to the disposable OPNsense WebGUI URL.');
|
throw new Error('Set OPNSENSE_UI_BASE_URL to the disposable OPNsense WebGUI URL.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hostname = new URL(baseURL).hostname;
|
||||||
|
const isLoopback = ['127.0.0.1', '::1', '[::1]', 'localhost'].includes(hostname);
|
||||||
|
|
||||||
|
if (!isLoopback && process.env.OPNSENSE_UI_TEST_ALLOW_REMOTE !== '1') {
|
||||||
|
throw new Error('Set OPNSENSE_UI_TEST_ALLOW_REMOTE=1 to test a remote disposable OPNsense deployment.');
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
testDir: './specs',
|
testDir: './specs',
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
workers: 1,
|
workers: 1,
|
||||||
use: {
|
use: {
|
||||||
baseURL,
|
baseURL,
|
||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: isLoopback,
|
||||||
trace: 'retain-on-failure',
|
trace: 'retain-on-failure',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,13 @@ test('renders and preserves NordVPN enrollment controls', async ({ page }) => {
|
||||||
await expect(failurePolicy.locator('option[value="fail_open"]')).toHaveText('Use direct egress');
|
await expect(failurePolicy.locator('option[value="fail_open"]')).toHaveText('Use direct egress');
|
||||||
|
|
||||||
const grid = page.getByRole('grid');
|
const grid = page.getByRole('grid');
|
||||||
const deleteButtons = grid.getByRole('button', { name: 'Delete', exact: true });
|
const testRows = grid.getByRole('row').filter({ hasText: 'UI_TEST_NETWORK' });
|
||||||
while (await deleteButtons.count()) {
|
while (await testRows.count()) {
|
||||||
const before = await deleteButtons.count();
|
const before = await testRows.count();
|
||||||
await deleteButtons.first().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(deleteButtons).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();
|
||||||
|
|
@ -104,12 +104,12 @@ test('renders and preserves NordVPN enrollment controls', async ({ page }) => {
|
||||||
await dialog.getByRole('button', { name: 'Close' }).click();
|
await dialog.getByRole('button', { name: 'Close' }).click();
|
||||||
await expect(dialog).toBeHidden();
|
await expect(dialog).toBeHidden();
|
||||||
|
|
||||||
const beforeDelete = await deleteButtons.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(deleteButtons).toHaveCount(beforeDelete - 1);
|
await expect(testRows).toHaveCount(beforeDelete - 1);
|
||||||
|
|
||||||
expect(errors).toEqual([]);
|
expect(errors).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue