Skip to content

Commit 2d6ac87

Browse files
committed
Fix open option to handle absolute URLs correctly
Fixes #7
1 parent f95a9e1 commit 2d6ac87

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

index.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ export type Options = {
2828
Open the server URL in the browser.
2929
3030
Can be one of the following:
31-
- `true`: Opens the default server URL (`http://${hostname}${port}`).
32-
- A relative URL: Opens that URL in the browser. Useful when testing pages that are not the default.
31+
- `true`: Opens the default server URL (`http://${hostname}:${port}`).
32+
- A relative path: Opens that path on the server (e.g., `'/about'` opens `http://${hostname}:${port}/about`).
33+
- An absolute URL: Opens that exact URL (e.g., `'http://localhost:3000'`).
3334
3435
@default false
3536
*/

index.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,23 @@ export default async function phpServer(options) {
130130
});
131131

132132
let pathname = '/';
133+
let openUrl = url;
134+
133135
if (typeof options.open === 'string') {
134-
pathname += options.open.replace(/^\//, '');
136+
// Check if it's an absolute URL
137+
try {
138+
// eslint-disable-next-line no-new
139+
new URL(options.open);
140+
// It's an absolute URL, use it as-is
141+
openUrl = options.open;
142+
// Extract pathname for server check
143+
const parsedUrl = new URL(options.open);
144+
pathname = parsedUrl.pathname;
145+
} catch {
146+
// It's a relative path, append to base URL
147+
pathname += options.open.replace(/^\//, '');
148+
openUrl = `${url}${pathname}`;
149+
}
135150
}
136151

137152
// Check when the server is ready. Tried doing it by listening
@@ -144,7 +159,7 @@ export default async function phpServer(options) {
144159
}
145160

146161
if (options.open) {
147-
await open(`${url}${pathname}`);
162+
await open(openUrl);
148163
}
149164

150165
return {

readme.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ Default: `false`
6969
Open the server URL in the browser.
7070

7171
Can be one of the following:
72-
- `true`: Opens the default server URL (`http://${hostname}${port}`).
73-
- A relative URL: Opens that URL in the browser. Useful when testing pages that are not the default.
72+
- `true`: Opens the default server URL (`http://${hostname}:${port}`).
73+
- A relative path: Opens that path on the server (e.g., `'/about'` opens `http://${hostname}:${port}/about`).
74+
- An absolute URL: Opens that exact URL (e.g., `'http://localhost:3000'`).
7475

7576
##### env
7677

test/open-url.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {test} from 'node:test';
2+
import assert from 'node:assert/strict';
3+
4+
// Test the URL parsing logic
5+
test('open option URL parsing', () => {
6+
// Test absolute URL detection
7+
const absoluteUrls = [
8+
'http://localhost:3000',
9+
'https://example.com',
10+
'http://127.0.0.1:8080/path',
11+
];
12+
13+
for (const url of absoluteUrls) {
14+
try {
15+
// eslint-disable-next-line no-new
16+
new URL(url);
17+
assert.ok(true, `${url} is correctly identified as absolute`);
18+
} catch {
19+
assert.fail(`${url} should be parsed as absolute URL`);
20+
}
21+
}
22+
23+
// Test relative path detection
24+
const relativePaths = [
25+
'/about',
26+
'page.php',
27+
'admin/dashboard',
28+
'index.html',
29+
];
30+
31+
for (const path of relativePaths) {
32+
try {
33+
// eslint-disable-next-line no-new
34+
new URL(path);
35+
assert.fail(`${path} should not be parsed as absolute URL`);
36+
} catch {
37+
assert.ok(true, `${path} is correctly identified as relative`);
38+
}
39+
}
40+
});
41+
42+
test('pathname extraction from absolute URLs', () => {
43+
const testCases = [
44+
{url: 'http://localhost:3000', expectedPath: '/'},
45+
{url: 'http://localhost:3000/', expectedPath: '/'},
46+
{url: 'http://localhost:3000/about', expectedPath: '/about'},
47+
{url: 'https://example.com/path/to/page', expectedPath: '/path/to/page'},
48+
];
49+
50+
for (const {url, expectedPath} of testCases) {
51+
const parsedUrl = new URL(url);
52+
assert.equal(parsedUrl.pathname, expectedPath, `Pathname for ${url} should be ${expectedPath}`);
53+
}
54+
});

0 commit comments

Comments
 (0)