Skip to content

Commit

Permalink
👍 Show stack-trace on plugin error
Browse files Browse the repository at this point in the history
  • Loading branch information
lambdalisue committed Nov 26, 2024
1 parent 74715fa commit 95a8dad
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 19 deletions.
4 changes: 3 additions & 1 deletion denops/@denops-private/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ class Plugin {
try {
return await this.#denops.dispatcher[fn](...args);
} catch (err) {
const errMsg = err instanceof Error ? err.message : String(err);
const errMsg = err instanceof Error

Check warning on line 278 in denops/@denops-private/service.ts

View check run for this annotation

Codecov / codecov/patch

denops/@denops-private/service.ts#L278

Added line #L278 was not covered by tests
? err.stack ?? err.message // Prefer 'stack' if available
: String(err);

Check warning on line 280 in denops/@denops-private/service.ts

View check run for this annotation

Codecov / codecov/patch

denops/@denops-private/service.ts#L280

Added line #L280 was not covered by tests
throw new Error(
`Failed to call '${fn}' API in '${this.name}': ${errMsg}`,
);
Expand Down
34 changes: 28 additions & 6 deletions tests/denops/runtime/functions/denops/request_async_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
assertArrayIncludes,
assertEquals,
assertObjectMatch,
assertStringIncludes,
} from "jsr:@std/assert@^1.0.1";
import { INVALID_PLUGIN_NAMES } from "/denops-testdata/invalid_plugin_names.ts";
import { resolveTestDataPath } from "/denops-testdata/resolve.ts";
Expand Down Expand Up @@ -131,21 +132,34 @@ testHost({

await t.step("calls failure callback", async () => {
await wait(() => host.call("eval", "len(g:__test_denops_events)"));
const result = await host.call(
"eval",
"g:__test_denops_events",
// deno-lint-ignore no-explicit-any
) as any[];
assertObjectMatch(
await host.call("eval", "g:__test_denops_events") as unknown[],
result,
{
0: [
"TestDenopsRequestAsyncFailure:Called",
[
{
message:
"Failed to call 'fail' API in 'dummy': Dummy failure",
name: "Error",
},
],
],
},
);
const message = result[0][1][0].message as string;
assertStringIncludes(
message,
"Failed to call 'fail' API in 'dummy': Error: Dummy failure",
);
assertStringIncludes(
message,
"dummy_dispatcher_plugin.ts:19:13",
"Error message should include the where the original error occurred",
);
});
});

Expand All @@ -165,21 +179,29 @@ testHost({

await t.step("calls failure callback", async () => {
await wait(() => host.call("eval", "len(g:__test_denops_events)"));
const result = await host.call(
"eval",
"g:__test_denops_events",
// deno-lint-ignore no-explicit-any
) as any[];
assertObjectMatch(
await host.call("eval", "g:__test_denops_events") as unknown[],
result,
{
0: [
"TestDenopsRequestAsyncFailure:Called",
[
{
message:
"Failed to call 'not_exist_method' API in 'dummy': this[#denops].dispatcher[fn] is not a function",
name: "Error",
},
],
],
},
);
const message = result[0][1][0].message as string;
assertStringIncludes(
message,
"Failed to call 'not_exist_method' API in 'dummy': TypeError: this[#denops].dispatcher[fn] is not a function",
);
});
});
});
Expand Down
34 changes: 22 additions & 12 deletions tests/denops/runtime/functions/denops/request_test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { assertEquals, assertRejects } from "jsr:@std/assert@^1.0.1";
import {
assertEquals,
assertInstanceOf,
assertRejects,
assertStringIncludes,
} from "jsr:@std/assert@^1.0.1";
import { INVALID_PLUGIN_NAMES } from "/denops-testdata/invalid_plugin_names.ts";
import { resolveTestDataPath } from "/denops-testdata/resolve.ts";
import { testHost } from "/denops-testutil/host.ts";
Expand Down Expand Up @@ -68,16 +73,21 @@ testHost({

await t.step("if the dispatcher method throws an error", async (t) => {
await t.step("throws an error", async () => {
await assertRejects(
() =>
host.call(
"denops#request",
"dummy",
"fail",
["foo"],
),
Error,
"Failed to call 'fail' API in 'dummy': Dummy failure",
const result = await host.call(
"denops#request",
"dummy",
"fail",
["foo"],
).catch((e) => e);
assertInstanceOf(result, Error);
assertStringIncludes(
result.message,
"Failed to call 'fail' API in 'dummy': Error: Dummy failure",
);
assertStringIncludes(
result.message,
"dummy_dispatcher_plugin.ts:19:13",
"Error message should include the where the original error occurred",
);
});
});
Expand All @@ -93,7 +103,7 @@ testHost({
["foo"],
),
Error,
"Failed to call 'not_exist_method' API in 'dummy': this[#denops].dispatcher[fn] is not a function",
"Failed to call 'not_exist_method' API in 'dummy': TypeError: this[#denops].dispatcher[fn] is not a function",
);
});
});
Expand Down

0 comments on commit 95a8dad

Please sign in to comment.