Spaces:
Runtime error
Runtime error
| import { describe, expect, it } from 'vitest' | |
| import { findTailscaleServePort, detectTailscaleServe, hasGwPathHandler } from '@/lib/tailscale-serve' | |
| // Realistic Tailscale Serve status JSON matching the structure returned by | |
| // `tailscale serve status --json` | |
| const TYPICAL_WEB_CONFIG = { | |
| 'myhost.tailb5729a.ts.net:8443': { | |
| Handlers: { | |
| '/': { Proxy: 'http://localhost:18789' }, | |
| }, | |
| }, | |
| 'myhost.tailb5729a.ts.net:8444': { | |
| Handlers: { | |
| '/': { Proxy: 'http://127.0.0.1:3000' }, | |
| }, | |
| }, | |
| 'myhost.tailb5729a.ts.net:3001': { | |
| Handlers: { | |
| '/': { Proxy: 'http://127.0.0.1:3002' }, | |
| }, | |
| }, | |
| } | |
| const GW_PATH_WEB_CONFIG = { | |
| 'myhost.tailb5729a.ts.net:443': { | |
| Handlers: { | |
| '/': { Proxy: 'http://127.0.0.1:3000' }, | |
| '/gw': { Proxy: 'http://127.0.0.1:18789' }, | |
| }, | |
| }, | |
| } | |
| describe('findTailscaleServePort', () => { | |
| it('finds the external port proxying to a given local port', () => { | |
| expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 18789)).toBe(8443) | |
| expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 3000)).toBe(8444) | |
| expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 3002)).toBe(3001) | |
| }) | |
| it('returns null when no handler matches the target port', () => { | |
| expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 9999)).toBeNull() | |
| }) | |
| it('returns null for null/undefined web config', () => { | |
| expect(findTailscaleServePort(null, 18789)).toBeNull() | |
| expect(findTailscaleServePort(undefined, 18789)).toBeNull() | |
| }) | |
| it('returns null for empty web config', () => { | |
| expect(findTailscaleServePort({}, 18789)).toBeNull() | |
| }) | |
| it('handles handlers without Proxy field', () => { | |
| const web = { | |
| 'myhost.ts.net:443': { | |
| Handlers: { | |
| '/': { Path: '/var/www' }, | |
| }, | |
| }, | |
| } | |
| expect(findTailscaleServePort(web, 3000)).toBeNull() | |
| }) | |
| it('matches proxy URLs with trailing slash', () => { | |
| const web = { | |
| 'myhost.ts.net:9000': { | |
| Handlers: { | |
| '/': { Proxy: 'http://127.0.0.1:4000/' }, | |
| }, | |
| }, | |
| } | |
| expect(findTailscaleServePort(web, 4000)).toBe(9000) | |
| }) | |
| it('does not match partial port numbers', () => { | |
| const web = { | |
| 'myhost.ts.net:443': { | |
| Handlers: { | |
| '/': { Proxy: 'http://127.0.0.1:18789' }, | |
| }, | |
| }, | |
| } | |
| // Port 1878 should not match a proxy to 18789 | |
| expect(findTailscaleServePort(web, 1878)).toBeNull() | |
| // Port 8789 should not match | |
| expect(findTailscaleServePort(web, 8789)).toBeNull() | |
| }) | |
| }) | |
| describe('detectTailscaleServe', () => { | |
| it('detects /gw path-based proxy', () => { | |
| expect(detectTailscaleServe(GW_PATH_WEB_CONFIG)).toBe(true) | |
| }) | |
| it('detects port-based proxy to gateway default port 18789', () => { | |
| expect(detectTailscaleServe(TYPICAL_WEB_CONFIG)).toBe(true) | |
| }) | |
| it('returns false when no gateway proxy found', () => { | |
| const web = { | |
| 'myhost.ts.net:3000': { | |
| Handlers: { | |
| '/': { Proxy: 'http://127.0.0.1:3000' }, | |
| }, | |
| }, | |
| } | |
| expect(detectTailscaleServe(web)).toBe(false) | |
| }) | |
| it('returns false for null/undefined web config', () => { | |
| expect(detectTailscaleServe(null)).toBe(false) | |
| expect(detectTailscaleServe(undefined)).toBe(false) | |
| }) | |
| it('returns false for empty web config with no config path', () => { | |
| expect(detectTailscaleServe({})).toBe(false) | |
| }) | |
| it('handles host entries with no Handlers', () => { | |
| const web = { 'myhost.ts.net:443': {} } | |
| expect(detectTailscaleServe(web)).toBe(false) | |
| }) | |
| }) | |
| describe('hasGwPathHandler', () => { | |
| it('returns true when /gw handler exists', () => { | |
| expect(hasGwPathHandler(GW_PATH_WEB_CONFIG)).toBe(true) | |
| }) | |
| it('returns false when no /gw handler exists', () => { | |
| expect(hasGwPathHandler(TYPICAL_WEB_CONFIG)).toBe(false) | |
| }) | |
| it('returns false for null/undefined', () => { | |
| expect(hasGwPathHandler(null)).toBe(false) | |
| expect(hasGwPathHandler(undefined)).toBe(false) | |
| }) | |
| }) | |