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:
Diffstat (limited to 'tests/captive-portal.spec.mjs')
-rw-r--r--tests/captive-portal.spec.mjs73
1 files changed, 41 insertions, 32 deletions
diff --git a/tests/captive-portal.spec.mjs b/tests/captive-portal.spec.mjs
index b6ad96b..acd2a40 100644
--- a/tests/captive-portal.spec.mjs
+++ b/tests/captive-portal.spec.mjs
@@ -2,8 +2,9 @@ import { test, expect } from '@playwright/test';
2 2
3const PORTAL_IP = process.env.TOLLGATE_IP || '192.168.4.1'; 3const PORTAL_IP = process.env.TOLLGATE_IP || '192.168.4.1';
4const PORTAL_URL = `http://${PORTAL_IP}`; 4const PORTAL_URL = `http://${PORTAL_IP}`;
5const API_URL = `http://${PORTAL_IP}:2121`;
5 6
6test.describe('Captive Portal - Phase 1', () => { 7test.describe('Captive Portal - Phase 2', () => {
7 8
8 test('portal page loads with TollGate branding', async ({ page }) => { 9 test('portal page loads with TollGate branding', async ({ page }) => {
9 await page.goto(PORTAL_URL); 10 await page.goto(PORTAL_URL);
@@ -11,65 +12,73 @@ test.describe('Captive Portal - Phase 1', () => {
11 await expect(page.locator('.subtitle')).toContainText('internet access'); 12 await expect(page.locator('.subtitle')).toContainText('internet access');
12 }); 13 });
13 14
14 test('portal shows price', async ({ page }) => { 15 test('portal shows price from API', async ({ page }) => {
15 await page.goto(PORTAL_URL); 16 await page.goto(PORTAL_URL);
16 const priceEl = page.locator('.price-amount'); 17 const priceEl = page.locator('.price-amount');
17 await expect(priceEl).not.toBeEmpty({ timeout: 5000 }); 18 await expect(priceEl).not.toBeEmpty({ timeout: 5000 });
18 }); 19 });
19 20
20 test('grant access button exists', async ({ page }) => { 21 test('portal has Cashu token input', async ({ page }) => {
21 await page.goto(PORTAL_URL); 22 await page.goto(PORTAL_URL);
22 const btn = page.locator('#grantBtn'); 23 const textarea = page.locator('#tokenInput');
23 await expect(btn).toBeVisible(); 24 await expect(textarea).toBeVisible();
24 await expect(btn).toHaveText(/Grant Free Access/i); 25 await expect(textarea).toHaveAttribute('placeholder', /cashuA/);
25 }); 26 });
26 27
27 test('click grant access shows connected', async ({ page }) => { 28 test('portal has Pay & Connect button', async ({ page }) => {
28 await page.goto(PORTAL_URL); 29 await page.goto(PORTAL_URL);
29 const btn = page.locator('#grantBtn'); 30 const btn = page.locator('#payBtn');
30 await btn.click(); 31 await expect(btn).toBeVisible();
31 const status = page.locator('#status.success'); 32 await expect(btn).toHaveText(/Pay/);
32 await expect(status).toBeVisible({ timeout: 10000 });
33 await expect(status).toContainText(/Connected/i);
34 }); 33 });
35 34
36 test('captive detection URIs return portal', async ({ page }) => { 35 test('captive detection URIs return 302 redirect', async ({ request }) => {
37 const uris = ['/generate_204', '/hotspot-detect.html', '/canonical.html', '/success.txt']; 36 const uris = ['/generate_204', '/hotspot-detect.html', '/canonical.html', '/success.txt'];
38 for (const uri of uris) { 37 for (const uri of uris) {
39 const resp = await page.goto(`${PORTAL_URL}${uri}`); 38 const resp = await request.fetch(`${PORTAL_URL}${uri}`, { maxRedirects: 0, ignoreHTTPSErrors: true });
40 expect(resp.status()).toBe(200); 39 expect(resp.status()).toBe(302);
41 const body = await resp.text(); 40 const location = resp.headers()['location'];
42 expect(body).toContain('TollGate'); 41 expect(location).toBe('http://192.168.4.1/');
43 } 42 }
44 }); 43 });
45 44
46 test('/api/status returns JSON with price', async ({ page }) => { 45 test('captive detection redirects to portal page', async ({ page }) => {
47 const resp = await page.goto(`${PORTAL_URL}/api/status`); 46 await page.goto(`${PORTAL_URL}/generate_204`);
48 expect(resp.status()).toBe(200); 47 await expect(page.locator('h1')).toHaveText('TollGate');
49 const data = await resp.json();
50 expect(data).toHaveProperty('connected');
51 expect(data).toHaveProperty('price');
52 expect(typeof data.price).toBe('number');
53 }); 48 });
54 49
55 test('/whoami returns mac address', async ({ page }) => { 50 test('/whoami returns ip and mac', async ({ page }) => {
56 const resp = await page.goto(`${PORTAL_URL}/whoami`); 51 const resp = await page.goto(`${API_URL}/whoami`);
57 expect(resp.status()).toBe(200); 52 expect(resp.status()).toBe(200);
58 const text = await resp.text(); 53 const text = await resp.text();
59 expect(text).toMatch(/^mac=/); 54 expect(text).toMatch(/ip=\d+\.\d+\.\d+\.\d+/);
55 expect(text).toMatch(/mac=[0-9a-f]{2}:/);
60 }); 56 });
61 57
62 test('/usage returns -1/-1 before auth', async ({ page }) => { 58 test('/usage returns -1/-1 before payment', async ({ page }) => {
63 const resp = await page.goto(`${PORTAL_URL}/usage`); 59 const resp = await page.goto(`${API_URL}/usage`);
64 expect(resp.status()).toBe(200); 60 expect(resp.status()).toBe(200);
65 const text = await resp.text(); 61 const text = await resp.text();
66 expect(text).toBe('-1/-1'); 62 expect(text).toBe('-1/-1');
67 }); 63 });
68 64
69 test('/reset_authentication works', async ({ page }) => { 65 test('API advertisement has correct structure', async ({ page }) => {
70 const resp = await page.goto(`${PORTAL_URL}/reset_authentication`); 66 const resp = await page.goto(API_URL);
71 expect(resp.status()).toBe(200); 67 expect(resp.status()).toBe(200);
72 const data = await resp.json(); 68 const data = await resp.json();
73 expect(data.status).toBe('reset'); 69 expect(data.kind).toBe(10021);
70 expect(data.tags).toBeDefined();
71 expect(data.tags.some(t => t[0] === 'price_per_step')).toBe(true);
72 expect(data.tags.some(t => t[0] === 'step_size')).toBe(true);
73 });
74
75 test('invalid token returns error', async ({ request }) => {
76 const resp = await request.fetch(API_URL, {
77 method: 'POST',
78 data: 'garbage_not_a_token'
79 });
80 expect(resp.status()).toBe(400);
81 const data = await resp.json();
82 expect(data.kind).toBe(21023);
74 }); 83 });
75}); 84});