Skip to content

Commit b2cd780

Browse files
committed
🌿 fix flaky tests for dispatcher
1 parent 7648a1e commit b2cd780

File tree

4 files changed

+175
-57
lines changed

4 files changed

+175
-57
lines changed

tests/denops/runtime/functions/denops/notify_test.ts

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { testHost } from "/denops-testutil/host.ts";
66
import { wait } from "/denops-testutil/wait.ts";
77

88
const ASYNC_DELAY = 100;
9+
const MESSAGE_DELAY = 200;
910

10-
const scriptValid = resolveTestDataPath("dummy_valid_plugin.ts");
11+
const scriptDispatcher = resolveTestDataPath("dummy_dispatcher_plugin.ts");
1112

1213
testHost({
1314
name: "denops#notify()",
@@ -24,6 +25,7 @@ testHost({
2425
await host.call("execute", [
2526
"let g:__test_denops_events = []",
2627
"autocmd User DenopsPlugin* call add(g:__test_denops_events, expand('<amatch>'))",
28+
"autocmd User DummyDispatcherPlugin:* call add(g:__test_denops_events, expand('<amatch>'))",
2729
], "");
2830

2931
for (const [plugin_name, label] of INVALID_PLUGIN_NAMES) {
@@ -38,23 +40,51 @@ testHost({
3840
// Load plugin and wait.
3941
await host.call("execute", [
4042
"let g:__test_denops_events = []",
41-
`call denops#plugin#load('dummyLoaded', '${scriptValid}')`,
43+
`call denops#plugin#load('dummy', '${scriptDispatcher}')`,
4244
], "");
4345
await wait(async () =>
4446
(await host.call("eval", "g:__test_denops_events") as string[])
45-
.includes("DenopsPluginPost:dummyLoaded")
47+
.includes("DenopsPluginPost:dummy")
4648
);
4749

48-
outputs = [];
49-
await host.call("denops#notify", "dummyLoaded", "test", ["foo"]);
50+
await t.step("returns immediately", async () => {
51+
await host.call("execute", [
52+
"let g:__test_denops_events = []",
53+
], "");
5054

51-
await t.step("returns immediately", () => {
52-
assertEquals(outputs, []);
55+
await host.call("denops#notify", "dummy", "test", ["foo"]);
56+
57+
assertEquals(await host.call("eval", "g:__test_denops_events"), []);
5358
});
5459

5560
await t.step("calls dispatcher method", async () => {
56-
await delay(ASYNC_DELAY);
57-
assertStringIncludes(outputs.join(""), 'This is test call: ["foo"]');
61+
await delay(100 + ASYNC_DELAY);
62+
assertEquals(await host.call("eval", "g:__test_denops_events"), [
63+
'DummyDispatcherPlugin:TestCalled:["foo"]',
64+
]);
65+
});
66+
67+
await t.step("if the dispatcher method is not exist", async (t) => {
68+
await t.step("returns immediately (flaky)", async () => {
69+
outputs = [];
70+
71+
await host.call(
72+
"denops#notify",
73+
"dummy",
74+
"not_exist_method",
75+
["foo"],
76+
);
77+
78+
assertEquals(outputs, []);
79+
});
80+
81+
await t.step("outputs an error message", async () => {
82+
await delay(MESSAGE_DELAY);
83+
assertStringIncludes(
84+
outputs.join(""),
85+
"Failed to call 'not_exist_method' API in 'dummy'",
86+
);
87+
});
5888
});
5989
});
6090
},

tests/denops/runtime/functions/denops/request_async_test.ts

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
import {
2+
assertArrayIncludes,
23
assertEquals,
34
assertObjectMatch,
4-
assertStringIncludes,
55
} from "jsr:@std/assert@^1.0.1";
6+
import { delay } from "jsr:@std/async@^1.0.1/delay";
67
import { INVALID_PLUGIN_NAMES } from "/denops-testdata/invalid_plugin_names.ts";
78
import { resolveTestDataPath } from "/denops-testdata/resolve.ts";
89
import { testHost } from "/denops-testutil/host.ts";
910
import { wait } from "/denops-testutil/wait.ts";
1011

11-
const scriptValid = resolveTestDataPath("dummy_valid_plugin.ts");
12+
const ASYNC_DELAY = 100;
13+
14+
const scriptDispatcher = resolveTestDataPath("dummy_dispatcher_plugin.ts");
1215

1316
testHost({
1417
name: "denops#request_async()",
1518
mode: "all",
1619
postlude: [
1720
"runtime plugin/denops.vim",
1821
],
19-
fn: async ({ host, t, stderr, mode }) => {
20-
let outputs: string[] = [];
21-
stderr.pipeTo(
22-
new WritableStream({ write: (s) => void outputs.push(s) }),
23-
).catch(() => {});
22+
fn: async ({ host, t }) => {
2423
await wait(() => host.call("eval", "denops#server#status() ==# 'running'"));
2524
await host.call("execute", [
2625
"let g:__test_denops_events = []",
2726
"autocmd User DenopsPlugin* call add(g:__test_denops_events, expand('<amatch>'))",
27+
"autocmd User DummyDispatcherPlugin:* call add(g:__test_denops_events, expand('<amatch>'))",
2828
"function TestDenopsRequestAsyncSuccess(...)",
29-
" call add(g:__test_denops_events, ['TestDenopsRequestAsyncSuccess', a:000])",
29+
" call add(g:__test_denops_events, ['TestDenopsRequestAsyncSuccess:Called', a:000])",
3030
"endfunction",
3131
"function TestDenopsRequestAsyncFailure(...)",
32-
" call add(g:__test_denops_events, ['TestDenopsRequestAsyncFailure', a:000])",
32+
" call add(g:__test_denops_events, ['TestDenopsRequestAsyncFailure:Called', a:000])",
3333
"endfunction",
3434
], "");
3535

@@ -53,10 +53,10 @@ testHost({
5353
await t.step("calls failure callback", async () => {
5454
await wait(() => host.call("eval", "len(g:__test_denops_events)"));
5555
assertObjectMatch(
56-
await host.call("eval", "g:__test_denops_events") as [],
56+
await host.call("eval", "g:__test_denops_events") as unknown[],
5757
{
5858
0: [
59-
"TestDenopsRequestAsyncFailure",
59+
"TestDenopsRequestAsyncFailure:Called",
6060
[
6161
{
6262
message: `Invalid plugin name: ${plugin_name}`,
@@ -74,43 +74,86 @@ testHost({
7474
// Load plugin and wait.
7575
await host.call("execute", [
7676
"let g:__test_denops_events = []",
77-
`call denops#plugin#load('dummyLoaded', '${scriptValid}')`,
77+
`call denops#plugin#load('dummy', '${scriptDispatcher}')`,
7878
], "");
7979
await wait(async () =>
8080
(await host.call("eval", "g:__test_denops_events") as string[])
81-
.includes("DenopsPluginPost:dummyLoaded")
81+
.includes("DenopsPluginPost:dummy")
8282
);
83-
await host.call("execute", [
84-
"let g:__test_denops_events = []",
85-
], "");
8683

87-
outputs = [];
88-
await host.call(
89-
"denops#request_async",
90-
"dummyLoaded",
91-
"test",
92-
["foo"],
93-
"TestDenopsRequestAsyncSuccess",
94-
"TestDenopsRequestAsyncFailure",
95-
);
84+
await t.step("returns immediately", async () => {
85+
await host.call("execute", [
86+
"let g:__test_denops_events = []",
87+
], "");
88+
89+
await host.call(
90+
"denops#request_async",
91+
"dummy",
92+
"test",
93+
["foo"],
94+
"TestDenopsRequestAsyncSuccess",
95+
"TestDenopsRequestAsyncFailure",
96+
);
9697

97-
await t.step("returns immediately", () => {
98-
assertEquals(outputs, []);
98+
assertEquals(await host.call("eval", "g:__test_denops_events"), []);
99+
});
100+
101+
await t.step("calls dispatcher method", async () => {
102+
await delay(100 + ASYNC_DELAY);
103+
assertArrayIncludes(
104+
await host.call("eval", "g:__test_denops_events") as unknown[],
105+
['DummyDispatcherPlugin:TestCalled:["foo"]'],
106+
);
99107
});
100108

101109
await t.step("calls success callback", async () => {
102-
await wait(() => host.call("eval", "len(g:__test_denops_events)"));
103-
const returnValue = mode === "vim" ? null : 0;
104-
assertObjectMatch(
105-
await host.call("eval", "g:__test_denops_events") as [],
106-
{
107-
0: ["TestDenopsRequestAsyncSuccess", [returnValue]],
108-
},
110+
assertArrayIncludes(
111+
await host.call("eval", "g:__test_denops_events") as unknown[],
112+
[
113+
[
114+
"TestDenopsRequestAsyncSuccess:Called",
115+
[{ result: "OK", args: ["foo"] }],
116+
],
117+
],
109118
);
110119
});
111120

112-
await t.step("calls dispatcher method", () => {
113-
assertStringIncludes(outputs.join(""), 'This is test call: ["foo"]');
121+
await t.step("if the dispatcher method is not exist", async (t) => {
122+
await t.step("returns immediately", async () => {
123+
await host.call("execute", [
124+
"let g:__test_denops_events = []",
125+
], "");
126+
127+
await host.call(
128+
"denops#request_async",
129+
"dummy",
130+
"not_exist_method",
131+
["foo"],
132+
"TestDenopsRequestAsyncSuccess",
133+
"TestDenopsRequestAsyncFailure",
134+
);
135+
136+
assertEquals(await host.call("eval", "g:__test_denops_events"), []);
137+
});
138+
139+
await t.step("calls failure callback", async () => {
140+
await wait(() => host.call("eval", "len(g:__test_denops_events)"));
141+
assertObjectMatch(
142+
await host.call("eval", "g:__test_denops_events") as unknown[],
143+
{
144+
0: [
145+
"TestDenopsRequestAsyncFailure:Called",
146+
[
147+
{
148+
message:
149+
"Failed to call 'not_exist_method' API in 'dummy': this[#denops].dispatcher[fn] is not a function",
150+
name: "Error",
151+
},
152+
],
153+
],
154+
},
155+
);
156+
});
114157
});
115158
});
116159
},

tests/denops/runtime/functions/denops/request_test.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
1-
import { assertRejects, assertStringIncludes } from "jsr:@std/assert@^1.0.1";
1+
import { assertEquals, assertRejects } from "jsr:@std/assert@^1.0.1";
22
import { INVALID_PLUGIN_NAMES } from "/denops-testdata/invalid_plugin_names.ts";
33
import { resolveTestDataPath } from "/denops-testdata/resolve.ts";
44
import { testHost } from "/denops-testutil/host.ts";
55
import { wait } from "/denops-testutil/wait.ts";
66

7-
const scriptValid = resolveTestDataPath("dummy_valid_plugin.ts");
7+
const scriptDispatcher = resolveTestDataPath("dummy_dispatcher_plugin.ts");
88

99
testHost({
1010
name: "denops#request()",
1111
mode: "all",
1212
postlude: [
1313
"runtime plugin/denops.vim",
1414
],
15-
fn: async ({ host, t, stderr }) => {
16-
let outputs: string[] = [];
17-
stderr.pipeTo(
18-
new WritableStream({ write: (s) => void outputs.push(s) }),
19-
).catch(() => {});
15+
fn: async ({ host, t }) => {
2016
await wait(() => host.call("eval", "denops#server#status() ==# 'running'"));
2117
await host.call("execute", [
2218
"let g:__test_denops_events = []",
2319
"autocmd User DenopsPlugin* call add(g:__test_denops_events, expand('<amatch>'))",
20+
"autocmd User DummyDispatcherPlugin:* call add(g:__test_denops_events, expand('<amatch>'))",
2421
], "");
2522

2623
for (const [plugin_name, label] of INVALID_PLUGIN_NAMES) {
@@ -39,18 +36,50 @@ testHost({
3936
// Load plugin and wait.
4037
await host.call("execute", [
4138
"let g:__test_denops_events = []",
42-
`call denops#plugin#load('dummyLoaded', '${scriptValid}')`,
39+
`call denops#plugin#load('dummy', '${scriptDispatcher}')`,
4340
], "");
4441
await wait(async () =>
4542
(await host.call("eval", "g:__test_denops_events") as string[])
46-
.includes("DenopsPluginPost:dummyLoaded")
43+
.includes("DenopsPluginPost:dummy")
4744
);
4845

4946
await t.step("calls dispatcher method", async () => {
50-
outputs = [];
51-
await host.call("denops#request", "dummyLoaded", "test", ["foo"]);
47+
await host.call("execute", [
48+
"let g:__test_denops_events = []",
49+
], "");
5250

53-
assertStringIncludes(outputs.join(""), 'This is test call: ["foo"]');
51+
await host.call("denops#request", "dummy", "test", ["foo"]);
52+
53+
assertEquals(await host.call("eval", "g:__test_denops_events"), [
54+
'DummyDispatcherPlugin:TestCalled:["foo"]',
55+
]);
56+
});
57+
58+
await t.step("returns dispatcher method return value", async () => {
59+
const result = await host.call(
60+
"denops#request",
61+
"dummy",
62+
"test",
63+
["foo"],
64+
);
65+
66+
assertEquals(result, { result: "OK", args: ["foo"] });
67+
});
68+
69+
await t.step("if the dispatcher method is not exist", async (t) => {
70+
await t.step("throws an error", async () => {
71+
await assertRejects(
72+
() =>
73+
host.call(
74+
"denops#request",
75+
"dummy",
76+
"not_exist_method",
77+
["foo"],
78+
),
79+
Error,
80+
"Failed to call 'not_exist_method' API in 'dummy'",
81+
);
82+
});
5483
});
5584
});
5685
},
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { delay } from "jsr:@std/async@^1.0.1/delay";
2+
import type { Entrypoint } from "jsr:@denops/core@^7.0.0";
3+
4+
export const main: Entrypoint = (denops) => {
5+
denops.dispatcher = {
6+
test: async (...args) => {
7+
await delay(100);
8+
await denops.cmd(
9+
`execute 'doautocmd <nomodeline> User' fnameescape('DummyDispatcherPlugin:TestCalled:${
10+
JSON.stringify(args)
11+
}')`,
12+
);
13+
return { result: "OK", args };
14+
},
15+
};
16+
};

0 commit comments

Comments
 (0)