Fix tests
This commit is contained in:
parent
d448111da5
commit
43ca6dcf07
6 changed files with 214 additions and 185 deletions
|
@ -23,15 +23,16 @@
|
|||
"test:coverage": "deno test --coverage=coverage --allow-net --allow-env --allow-read --allow-run --allow-sys tests/ && deno coverage coverage"
|
||||
},
|
||||
"imports": {
|
||||
"std/": "https://deno.land/std@0.220.0/",
|
||||
"node/": "https://deno.land/std@0.220.0/node/",
|
||||
"std/": "https://deno.land/std@0.224.0/",
|
||||
"node/": "https://deno.land/std@0.224.0/node/",
|
||||
"@modelcontextprotocol/sdk/": "npm:@modelcontextprotocol/sdk/"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"DOM"
|
||||
"DOM",
|
||||
"deno.ns"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
97
deno.lock
generated
97
deno.lock
generated
|
@ -1358,59 +1358,50 @@
|
|||
}
|
||||
},
|
||||
"remote": {
|
||||
"https://deno.land/std@0.218.2/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
|
||||
"https://deno.land/std@0.218.2/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840",
|
||||
"https://deno.land/std@0.218.2/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4",
|
||||
"https://deno.land/std@0.218.2/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e",
|
||||
"https://deno.land/std@0.218.2/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2",
|
||||
"https://deno.land/std@0.218.2/assert/assert_rejects.ts": "5206ac37d883797d9504e3915a0c7b692df6efcdefff3889cc14bb5a325641dd",
|
||||
"https://deno.land/std@0.218.2/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
|
||||
"https://deno.land/std@0.218.2/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2",
|
||||
"https://deno.land/std@0.218.2/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a",
|
||||
"https://deno.land/std@0.218.2/testing/mock.ts": "dc9e58f88f7e746edd0c551443a39096c75895a0fdcd7db62777e47787be6226",
|
||||
"https://deno.land/std@0.220.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
|
||||
"https://deno.land/std@0.220.0/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b",
|
||||
"https://deno.land/std@0.220.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4",
|
||||
"https://deno.land/std@0.220.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5",
|
||||
"https://deno.land/std@0.220.0/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f",
|
||||
"https://deno.land/std@0.220.0/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1",
|
||||
"https://deno.land/std@0.220.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e",
|
||||
"https://deno.land/std@0.220.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9",
|
||||
"https://deno.land/std@0.220.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769",
|
||||
"https://deno.land/std@0.220.0/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c",
|
||||
"https://deno.land/std@0.220.0/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219",
|
||||
"https://deno.land/std@0.220.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444",
|
||||
"https://deno.land/std@0.220.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2",
|
||||
"https://deno.land/std@0.220.0/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005",
|
||||
"https://deno.land/std@0.220.0/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0",
|
||||
"https://deno.land/std@0.220.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1",
|
||||
"https://deno.land/std@0.220.0/assert/assert_not_equals.ts": "ac86413ab70ffb14fdfc41740ba579a983fe355ba0ce4a9ab685e6b8e7f6a250",
|
||||
"https://deno.land/std@0.220.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931",
|
||||
"https://deno.land/std@0.220.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f",
|
||||
"https://deno.land/std@0.220.0/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be",
|
||||
"https://deno.land/std@0.220.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49",
|
||||
"https://deno.land/std@0.220.0/assert/assert_rejects.ts": "5206ac37d883797d9504e3915a0c7b692df6efcdefff3889cc14bb5a325641dd",
|
||||
"https://deno.land/std@0.220.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366",
|
||||
"https://deno.land/std@0.220.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7",
|
||||
"https://deno.land/std@0.220.0/assert/assert_throws.ts": "31f3c061338aec2c2c33731973d58ccd4f14e42f355501541409ee958d2eb8e5",
|
||||
"https://deno.land/std@0.220.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
|
||||
"https://deno.land/std@0.220.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2",
|
||||
"https://deno.land/std@0.220.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c",
|
||||
"https://deno.land/std@0.220.0/assert/mod.ts": "7e41449e77a31fef91534379716971bebcfc12686e143d38ada5438e04d4a90e",
|
||||
"https://deno.land/std@0.220.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd",
|
||||
"https://deno.land/std@0.220.0/assert/unreachable.ts": "3670816a4ab3214349acb6730e3e6f5299021234657eefe05b48092f3848c270",
|
||||
"https://deno.land/std@0.220.0/async/delay.ts": "8e1d18fe8b28ff95885e2bc54eccec1713f57f756053576d8228e6ca110793ad",
|
||||
"https://deno.land/std@0.220.0/data_structures/_binary_search_node.ts": "ce1da11601fef0638df4d1e53c377f791f96913383277389286b390685d76c07",
|
||||
"https://deno.land/std@0.220.0/data_structures/_red_black_node.ts": "4af8d3c5ac5f119d8058269259c46ea22ead567246cacde04584a83e43a9d2ea",
|
||||
"https://deno.land/std@0.220.0/data_structures/binary_search_tree.ts": "2dd43d97ce5f5a4bdba11b075eb458db33e9143f50997b0eebf02912cb44f5d5",
|
||||
"https://deno.land/std@0.220.0/data_structures/comparators.ts": "74e64752f005f03614d9bd4912ea64c58d2e663b5d8c9dba6e2e2997260f51eb",
|
||||
"https://deno.land/std@0.220.0/data_structures/red_black_tree.ts": "2222be0c46842fc932e2c8589a66dced9e6eae180914807c5c55d1aa4c8c1b9b",
|
||||
"https://deno.land/std@0.220.0/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a",
|
||||
"https://deno.land/std@0.220.0/testing/_test_suite.ts": "f10a8a6338b60c403f07a76f3f46bdc9f1e1a820c0a1decddeb2949f7a8a0546",
|
||||
"https://deno.land/std@0.220.0/testing/_time.ts": "fefd1ff35b50a410db9b0e7227e05163e1b172c88afd0d2071df0125958c3ff3",
|
||||
"https://deno.land/std@0.220.0/testing/bdd.ts": "7a8ac58eded80e6fefa7cf7538927e88781cf5f247c04b35261c3213316e2dd0",
|
||||
"https://deno.land/std@0.220.0/testing/mock.ts": "a963181c2860b6ba3eb60e08b62c164d33cf5da7cd445893499b2efda20074db",
|
||||
"https://deno.land/std@0.220.0/testing/time.ts": "0d25e0f15eded2d66c9ed37d16c3188b16cc1aefa58be4a4753afb7750e72cb0"
|
||||
"https://deno.land/std@0.224.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
|
||||
"https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
|
||||
"https://deno.land/std@0.224.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293",
|
||||
"https://deno.land/std@0.224.0/assert/assert_array_includes.ts": "14c5094471bc8e4a7895fc6aa5a184300d8a1879606574cb1cd715ef36a4a3c7",
|
||||
"https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74",
|
||||
"https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd",
|
||||
"https://deno.land/std@0.224.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff",
|
||||
"https://deno.land/std@0.224.0/assert/assert_greater.ts": "5e57b201fd51b64ced36c828e3dfd773412c1a6120c1a5a99066c9b261974e46",
|
||||
"https://deno.land/std@0.224.0/assert/assert_greater_or_equal.ts": "9870030f997a08361b6f63400273c2fb1856f5db86c0c3852aab2a002e425c5b",
|
||||
"https://deno.land/std@0.224.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c",
|
||||
"https://deno.land/std@0.224.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491",
|
||||
"https://deno.land/std@0.224.0/assert/assert_less.ts": "60b61e13a1982865a72726a5fa86c24fad7eb27c3c08b13883fb68882b307f68",
|
||||
"https://deno.land/std@0.224.0/assert/assert_less_or_equal.ts": "d2c84e17faba4afe085e6c9123a63395accf4f9e00150db899c46e67420e0ec3",
|
||||
"https://deno.land/std@0.224.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7",
|
||||
"https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29",
|
||||
"https://deno.land/std@0.224.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a",
|
||||
"https://deno.land/std@0.224.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a",
|
||||
"https://deno.land/std@0.224.0/assert/assert_not_strict_equals.ts": "37f73880bd672709373d6dc2c5f148691119bed161f3020fff3548a0496f71b8",
|
||||
"https://deno.land/std@0.224.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693",
|
||||
"https://deno.land/std@0.224.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31",
|
||||
"https://deno.land/std@0.224.0/assert/assert_strict_equals.ts": "b4f45f0fd2e54d9029171876bd0b42dd9ed0efd8f853ab92a3f50127acfa54f5",
|
||||
"https://deno.land/std@0.224.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8",
|
||||
"https://deno.land/std@0.224.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb",
|
||||
"https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
|
||||
"https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47",
|
||||
"https://deno.land/std@0.224.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68",
|
||||
"https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3",
|
||||
"https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73",
|
||||
"https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19",
|
||||
"https://deno.land/std@0.224.0/async/delay.ts": "f90dd685b97c2f142b8069082993e437b1602b8e2561134827eeb7c12b95c499",
|
||||
"https://deno.land/std@0.224.0/data_structures/_binary_search_node.ts": "ce1da11601fef0638df4d1e53c377f791f96913383277389286b390685d76c07",
|
||||
"https://deno.land/std@0.224.0/data_structures/_red_black_node.ts": "4af8d3c5ac5f119d8058269259c46ea22ead567246cacde04584a83e43a9d2ea",
|
||||
"https://deno.land/std@0.224.0/data_structures/binary_search_tree.ts": "2dd43d97ce5f5a4bdba11b075eb458db33e9143f50997b0eebf02912cb44f5d5",
|
||||
"https://deno.land/std@0.224.0/data_structures/comparators.ts": "17dfa68bf1550edadbfdd453a06f9819290bcb534c9945b5cec4b30242cff475",
|
||||
"https://deno.land/std@0.224.0/data_structures/red_black_tree.ts": "2222be0c46842fc932e2c8589a66dced9e6eae180914807c5c55d1aa4c8c1b9b",
|
||||
"https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
|
||||
"https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
|
||||
"https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
|
||||
"https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
|
||||
"https://deno.land/std@0.224.0/testing/_test_suite.ts": "f10a8a6338b60c403f07a76f3f46bdc9f1e1a820c0a1decddeb2949f7a8a0546",
|
||||
"https://deno.land/std@0.224.0/testing/_time.ts": "fefd1ff35b50a410db9b0e7227e05163e1b172c88afd0d2071df0125958c3ff3",
|
||||
"https://deno.land/std@0.224.0/testing/bdd.ts": "3e4de4ff6d8f348b5574661cef9501b442046a59079e201b849d0e74120d476b",
|
||||
"https://deno.land/std@0.224.0/testing/mock.ts": "a963181c2860b6ba3eb60e08b62c164d33cf5da7cd445893499b2efda20074db",
|
||||
"https://deno.land/std@0.224.0/testing/time.ts": "7119072a198e9913da0d21106b1f05a90a4c05b07075529770ff0e2a9eb5eaba"
|
||||
},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Implmentation Plan
|
||||
# Implementation Plan
|
||||
|
||||
Here is a plan to transform your Node.js CLI package into a Deno CLI project, focusing on reusing the existing TypeScript code in the `src/` directory:
|
||||
|
|
@ -1,70 +1,120 @@
|
|||
import { delay } from "std/async/delay.ts";
|
||||
|
||||
/**
|
||||
* Opens a URL in the default browser.
|
||||
* This is a cross-platform implementation using Deno subprocess API
|
||||
* @param url The URL to open
|
||||
* @returns A promise that resolves when the command has been executed
|
||||
* Options for the open function.
|
||||
*/
|
||||
export default async function open(url: string): Promise<void> {
|
||||
let command: string[];
|
||||
const isWindows = Deno.build.os === "windows";
|
||||
const isMac = Deno.build.os === "darwin";
|
||||
const isLinux = Deno.build.os === "linux";
|
||||
export interface OpenOptions {
|
||||
/**
|
||||
* Specify the operating system ('windows', 'darwin', 'linux').
|
||||
* Defaults to Deno.build.os. Useful for testing.
|
||||
*/
|
||||
os?: string;
|
||||
/**
|
||||
* Specify an application to open the URL/file with.
|
||||
*/
|
||||
app?: string;
|
||||
/**
|
||||
* Wait for the opened application to exit before resolving the promise.
|
||||
* If the application closes instantly, wait for 1 second.
|
||||
*/
|
||||
wait?: boolean;
|
||||
/**
|
||||
* Use 'background' on macOS to open the application in the background.
|
||||
*/
|
||||
background?: boolean; // Relevant for macOS 'open' command
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the given URL or file path using the default application,
|
||||
* or a specified application.
|
||||
*
|
||||
* @param target The URL or file path to open.
|
||||
* @param options Optional configuration for opening the target.
|
||||
*/
|
||||
export default async function open(
|
||||
target: string,
|
||||
options?: OpenOptions,
|
||||
): Promise<void> {
|
||||
const currentOs = options?.os ?? Deno.build.os;
|
||||
const isWindows = currentOs === "windows";
|
||||
const isMac = currentOs === "darwin";
|
||||
const isLinux = currentOs === "linux"; // Handle Linux as well
|
||||
|
||||
let command: string;
|
||||
const args: string[] = [];
|
||||
|
||||
if (isWindows) {
|
||||
command = ["cmd", "/c", "start", "", url];
|
||||
} else if (isMac) {
|
||||
command = ["open", url];
|
||||
} else if (isLinux) {
|
||||
// On Linux, try several common browser-opener commands
|
||||
const linuxCommands = [
|
||||
["xdg-open", url],
|
||||
["gnome-open", url],
|
||||
["kde-open", url],
|
||||
["wslview", url] // For Windows Subsystem for Linux
|
||||
];
|
||||
command = "cmd";
|
||||
args.push("/c", "start", '""'); // Use empty title
|
||||
|
||||
// Try each command in order until one succeeds
|
||||
for (const cmd of linuxCommands) {
|
||||
try {
|
||||
const process = new Deno.Command(cmd[0], {
|
||||
args: cmd.slice(1),
|
||||
stdout: "null",
|
||||
stderr: "null"
|
||||
}).spawn();
|
||||
|
||||
const status = await process.status;
|
||||
|
||||
if (status.success) {
|
||||
return; // Command succeeded, so exit the function
|
||||
}
|
||||
} catch {
|
||||
// If this command fails, try the next one
|
||||
}
|
||||
if (options?.wait) {
|
||||
args.push("/wait");
|
||||
}
|
||||
|
||||
// If we get here, none of the commands worked
|
||||
throw new Error("Could not open browser on Linux. Please open URL manually.");
|
||||
if (options?.app) {
|
||||
args.push(options.app);
|
||||
}
|
||||
|
||||
args.push(target.replace(/&/g, "^&")); // Escape ampersands for cmd
|
||||
} else {
|
||||
throw new Error(`Unsupported platform: ${Deno.build.os}`);
|
||||
// Common logic for macOS and Linux, potentially differing commands
|
||||
if (isMac) {
|
||||
command = "open";
|
||||
if (options?.wait) {
|
||||
args.push("-W");
|
||||
}
|
||||
if (options?.background) {
|
||||
args.push("-g"); // Use -g for background on macOS
|
||||
}
|
||||
if (options?.app) {
|
||||
args.push("-a", options.app);
|
||||
}
|
||||
} else if (isLinux) {
|
||||
// Try common Linux commands - may need adjustment based on distribution
|
||||
command = options?.app ? options.app : "xdg-open"; // Use specific app or xdg-open
|
||||
// Note: Wait behavior might be inconsistent on Linux with xdg-open
|
||||
} else {
|
||||
throw new Error(`Unsupported platform: ${currentOs}`);
|
||||
}
|
||||
args.push(target);
|
||||
}
|
||||
|
||||
// For Windows and Mac, execute the chosen command
|
||||
if (isWindows || isMac) {
|
||||
try {
|
||||
const process = new Deno.Command(command[0], {
|
||||
args: command.slice(1),
|
||||
stdout: "null",
|
||||
stderr: "null"
|
||||
}).spawn();
|
||||
const process = new Deno.Command(command, {
|
||||
args: args,
|
||||
// Use 'piped' or 'null' for testing to avoid interfering with test output
|
||||
// For actual use, 'inherit' might be desired, but makes testing harder.
|
||||
stdout: "piped", // Capture stdout
|
||||
stderr: "piped", // Capture stderr
|
||||
});
|
||||
|
||||
const status = await process.status;
|
||||
// Use output() to wait for the command and get status/output
|
||||
const { success, code, stdout, stderr } = await process.output();
|
||||
|
||||
if (!status.success) {
|
||||
throw new Error(`Failed to open ${url} in browser`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Failed to open ${url} in browser: ${errorMessage}`);
|
||||
if (!success) {
|
||||
const errorDetails = new TextDecoder().decode(stderr).trim();
|
||||
const stdoutDetails = new TextDecoder().decode(stdout).trim();
|
||||
let errorMessage = `Failed to open "${target}". Command "${command} ${args.join(" ")}" exited with code ${code}.`;
|
||||
if (errorDetails) errorMessage += `\nStderr: ${errorDetails}`;
|
||||
if (stdoutDetails) errorMessage += `\nStdout: ${stdoutDetails}`; // Include stdout too
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Handle 'wait' specifically on macOS/Linux if needed, as process.output() already waits.
|
||||
// The 'wait' option for cmd /c start /wait is handled by the command itself.
|
||||
// For macOS 'open -W', output() correctly waits.
|
||||
// For Linux, if wait is true and we used xdg-open, true waiting might not be possible easily.
|
||||
// We might need a fallback sleep if 'wait' is requested on Linux without a specific app.
|
||||
if (options?.wait && isLinux && !options?.app) {
|
||||
// xdg-open often returns immediately. Add a small delay as a basic wait.
|
||||
await delay(1000); // Wait 1 second (adjust as necessary)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (error instanceof Deno.errors.NotFound) {
|
||||
throw new Error(`Failed to open "${target}": Command not found: ${command}`);
|
||||
}
|
||||
// Re-throw other errors or wrap them
|
||||
throw error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ describe("DenoHttpServer", () => {
|
|||
|
||||
// Verify the response
|
||||
assertEquals(response.status, 404);
|
||||
await response.body?.cancel(); // Consume the body to prevent leaks
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -5,7 +5,12 @@ import open from "../src/lib/deno-open.ts";
|
|||
|
||||
// Define the expected structure returned by the mocked Deno.Command
|
||||
interface MockCommandOutput {
|
||||
spawn: () => { status: Promise<{ success: boolean; code: number }> };
|
||||
output: () => Promise<{
|
||||
success: boolean;
|
||||
code: number;
|
||||
stdout: Uint8Array;
|
||||
stderr: Uint8Array;
|
||||
}>;
|
||||
}
|
||||
|
||||
describe("deno-open", () => {
|
||||
|
@ -26,88 +31,69 @@ describe("deno-open", () => {
|
|||
});
|
||||
|
||||
it("calls the correct command on macOS", async () => {
|
||||
// Save original OS detection
|
||||
const originalOs = Deno.build.os;
|
||||
|
||||
try {
|
||||
// Mock OS detection - pretend we're on macOS
|
||||
Object.defineProperty(Deno.build, "os", { value: "darwin", configurable: true });
|
||||
|
||||
// Mock Deno.Command implementation
|
||||
const mockSpawn = { status: Promise.resolve({ success: true, code: 0 }) };
|
||||
const mockCommandConstructor = () => ({ spawn: () => mockSpawn });
|
||||
// Mock Deno.Command implementation to return success
|
||||
const mockOutput = {
|
||||
success: true,
|
||||
code: 0,
|
||||
stdout: new Uint8Array(),
|
||||
stderr: new Uint8Array(),
|
||||
};
|
||||
const mockCommandConstructor = () => ({ output: () => Promise.resolve(mockOutput) });
|
||||
commandSpy = spy(mockCommandConstructor);
|
||||
(Deno.Command as unknown) = commandSpy;
|
||||
|
||||
// Call open
|
||||
// Call open, specifying macOS in options
|
||||
const url = "https://example.com";
|
||||
await open(url);
|
||||
await open(url, { os: "darwin" });
|
||||
|
||||
// Verify the spy was called with correct arguments
|
||||
assertSpyCalls(commandSpy, 1);
|
||||
assertEquals(commandSpy.calls[0].args[0], "open");
|
||||
assertEquals((commandSpy.calls[0].args[1] as { args: string[] }).args[0], url);
|
||||
} finally {
|
||||
// Restore original OS detection
|
||||
Object.defineProperty(Deno.build, "os", { value: originalOs, configurable: true });
|
||||
}
|
||||
assertEquals(commandSpy.calls[0].args[1]?.args, [url]);
|
||||
});
|
||||
|
||||
it("calls the correct command on Windows", async () => {
|
||||
// Save original OS detection
|
||||
const originalOs = Deno.build.os;
|
||||
|
||||
try {
|
||||
// Mock OS detection - pretend we're on Windows
|
||||
Object.defineProperty(Deno.build, "os", { value: "windows", configurable: true });
|
||||
|
||||
// Mock Deno.Command implementation
|
||||
const mockSpawn = { status: Promise.resolve({ success: true, code: 0 }) };
|
||||
const mockCommandConstructor = () => ({ spawn: () => mockSpawn });
|
||||
// Mock Deno.Command implementation to return success
|
||||
const mockOutput = {
|
||||
success: true,
|
||||
code: 0,
|
||||
stdout: new Uint8Array(),
|
||||
stderr: new Uint8Array(),
|
||||
};
|
||||
const mockCommandConstructor = () => ({ output: () => Promise.resolve(mockOutput) });
|
||||
commandSpy = spy(mockCommandConstructor);
|
||||
(Deno.Command as unknown) = commandSpy;
|
||||
|
||||
// Call open
|
||||
// Call open, specifying windows in options
|
||||
const url = "https://example.com";
|
||||
await open(url);
|
||||
await open(url, { os: "windows" });
|
||||
|
||||
// Verify the spy was called with correct arguments
|
||||
assertSpyCalls(commandSpy, 1);
|
||||
assertEquals(commandSpy.calls[0].args[0], "cmd");
|
||||
assertEquals((commandSpy.calls[0].args[1] as { args: string[] }).args[0], "/c");
|
||||
assertEquals((commandSpy.calls[0].args[1] as { args: string[] }).args[1], "start");
|
||||
assertEquals((commandSpy.calls[0].args[1] as { args: string[] }).args[2], "");
|
||||
assertEquals((commandSpy.calls[0].args[1] as { args: string[] }).args[3], url);
|
||||
} finally {
|
||||
// Restore original OS detection
|
||||
Object.defineProperty(Deno.build, "os", { value: originalOs, configurable: true });
|
||||
}
|
||||
assertEquals(commandSpy.calls[0].args[1]?.args, ["/c", "start", '""', url]);
|
||||
});
|
||||
|
||||
it("throws error on command failure", async () => {
|
||||
// Save original OS detection
|
||||
const originalOs = Deno.build.os;
|
||||
|
||||
try {
|
||||
// Mock OS detection
|
||||
Object.defineProperty(Deno.build, "os", { value: "darwin", configurable: true });
|
||||
|
||||
// Mock Deno.Command to return failure
|
||||
const mockSpawn = { status: Promise.resolve({ success: false, code: 1 }) };
|
||||
const mockCommandConstructor = () => ({ spawn: () => mockSpawn });
|
||||
const stderrOutput = new TextEncoder().encode("Command failed error message");
|
||||
const mockOutput = {
|
||||
success: false,
|
||||
code: 1,
|
||||
stdout: new Uint8Array(),
|
||||
stderr: stderrOutput,
|
||||
};
|
||||
const mockCommandConstructor = () => ({ output: () => Promise.resolve(mockOutput) });
|
||||
commandSpy = spy(mockCommandConstructor);
|
||||
(Deno.Command as unknown) = commandSpy;
|
||||
|
||||
// Call open and expect it to throw
|
||||
const url = "https://example.com";
|
||||
await assertRejects(
|
||||
() => open("https://example.com"),
|
||||
() => open(url, { os: "darwin" }),
|
||||
Error,
|
||||
"Failed to open"
|
||||
`Failed to open "${url}". Command "open ${url}" exited with code 1.\nStderr: Command failed error message`,
|
||||
);
|
||||
assertSpyCalls(commandSpy, 1);
|
||||
} finally {
|
||||
// Restore original OS detection
|
||||
Object.defineProperty(Deno.build, "os", { value: originalOs, configurable: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue