upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/tests/captive-portal.spec.mjs
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-15 17:03:40 +0530
committerYour Name <you@example.com>2026-05-15 17:03:40 +0530
commita7d0a672d59bf8985a6fc0e61b49015fabd96513 (patch)
tree46814d1757649a640f53805a8d9dfc1b0f354289 /tests/captive-portal.spec.mjs
parent8a2307a5ced6da94cc674602219d5a68a1246264 (diff)
Phase 1 working: captive portal, DNS hijack, NAT-based access control
- Fix WiFi init order: netif creation before esp_wifi_init, set mode before set_config - Replace broken netif input filter with NAPT on/off per authentication state - NAPT disabled by default, enabled when client granted, disabled on revoke - Fix test helpers: use -I wlp59s0 for ping, handle nslookup exit code 1 - All 20 API tests pass, all 6 smoke tests pass
Diffstat (limited to 'tests/captive-portal.spec.mjs')
-rw-r--r--tests/captive-portal.spec.mjs75
1 files changed, 75 insertions, 0 deletions
diff --git a/tests/captive-portal.spec.mjs b/tests/captive-portal.spec.mjs
new file mode 100644
index 0000000..b6ad96b
--- /dev/null
+++ b/tests/captive-portal.spec.mjs
@@ -0,0 +1,75 @@
1import { test, expect } from '@playwright/test';
2
3const PORTAL_IP = process.env.TOLLGATE_IP || '192.168.4.1';
4const PORTAL_URL = `http://${PORTAL_IP}`;
5
6test.describe('Captive Portal - Phase 1', () => {
7
8 test('portal page loads with TollGate branding', async ({ page }) => {
9 await page.goto(PORTAL_URL);
10 await expect(page.locator('h1')).toHaveText('TollGate');
11 await expect(page.locator('.subtitle')).toContainText('internet access');
12 });
13
14 test('portal shows price', async ({ page }) => {
15 await page.goto(PORTAL_URL);
16 const priceEl = page.locator('.price-amount');
17 await expect(priceEl).not.toBeEmpty({ timeout: 5000 });
18 });
19
20 test('grant access button exists', async ({ page }) => {
21 await page.goto(PORTAL_URL);
22 const btn = page.locator('#grantBtn');
23 await expect(btn).toBeVisible();
24 await expect(btn).toHaveText(/Grant Free Access/i);
25 });
26
27 test('click grant access shows connected', async ({ page }) => {
28 await page.goto(PORTAL_URL);
29 const btn = page.locator('#grantBtn');
30 await btn.click();
31 const status = page.locator('#status.success');
32 await expect(status).toBeVisible({ timeout: 10000 });
33 await expect(status).toContainText(/Connected/i);
34 });
35
36 test('captive detection URIs return portal', async ({ page }) => {
37 const uris = ['/generate_204', '/hotspot-detect.html', '/canonical.html', '/success.txt'];
38 for (const uri of uris) {
39 const resp = await page.goto(`${PORTAL_URL}${uri}`);
40 expect(resp.status()).toBe(200);
41 const body = await resp.text();
42 expect(body).toContain('TollGate');
43 }
44 });
45
46 test('/api/status returns JSON with price', async ({ page }) => {
47 const resp = await page.goto(`${PORTAL_URL}/api/status`);
48 expect(resp.status()).toBe(200);
49 const data = await resp.json();
50 expect(data).toHaveProperty('connected');
51 expect(data).toHaveProperty('price');
52 expect(typeof data.price).toBe('number');
53 });
54
55 test('/whoami returns mac address', async ({ page }) => {
56 const resp = await page.goto(`${PORTAL_URL}/whoami`);
57 expect(resp.status()).toBe(200);
58 const text = await resp.text();
59 expect(text).toMatch(/^mac=/);
60 });
61
62 test('/usage returns -1/-1 before auth', async ({ page }) => {
63 const resp = await page.goto(`${PORTAL_URL}/usage`);
64 expect(resp.status()).toBe(200);
65 const text = await resp.text();
66 expect(text).toBe('-1/-1');
67 });
68
69 test('/reset_authentication works', async ({ page }) => {
70 const resp = await page.goto(`${PORTAL_URL}/reset_authentication`);
71 expect(resp.status()).toBe(200);
72 const data = await resp.json();
73 expect(data.status).toBe('reset');
74 });
75});