@player-ui/async-node-plugin 0.8.0-next.1 → 0.8.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AsyncNodePlugin.native.js +300 -324
- package/dist/AsyncNodePlugin.native.js.map +1 -1
- package/dist/cjs/index.cjs +73 -64
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +73 -64
- package/dist/index.mjs +73 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.test.ts +443 -327
- package/src/index.ts +101 -80
- package/types/index.d.ts +22 -4
package/src/index.test.ts
CHANGED
|
@@ -1,453 +1,569 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
1
|
+
import { expect, test, describe } from "vitest";
|
|
2
2
|
import { Node, InProgressState, ViewInstance } from "@player-ui/player";
|
|
3
|
-
import { Player } from "@player-ui/player";
|
|
3
|
+
import { Player, Parser } from "@player-ui/player";
|
|
4
4
|
import { waitFor } from "@testing-library/react";
|
|
5
5
|
import { AsyncNodePlugin, AsyncNodePluginPlugin } from "./index";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
describe("view", () => {
|
|
8
|
+
const basicFRFWithActions = {
|
|
9
|
+
id: "test-flow",
|
|
10
|
+
views: [
|
|
11
|
+
{
|
|
12
|
+
id: "my-view",
|
|
13
|
+
actions: [
|
|
14
|
+
{
|
|
15
|
+
asset: {
|
|
16
|
+
id: "action-0",
|
|
17
|
+
type: "action",
|
|
18
|
+
value: "{{foo.bar}}",
|
|
19
|
+
},
|
|
18
20
|
},
|
|
21
|
+
{
|
|
22
|
+
id: "nodeId",
|
|
23
|
+
async: "true",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
navigation: {
|
|
29
|
+
BEGIN: "FLOW_1",
|
|
30
|
+
FLOW_1: {
|
|
31
|
+
startState: "VIEW_1",
|
|
32
|
+
VIEW_1: {
|
|
33
|
+
state_type: "VIEW",
|
|
34
|
+
ref: "my-view",
|
|
35
|
+
transitions: {},
|
|
19
36
|
},
|
|
20
|
-
{
|
|
21
|
-
id: "nodeId",
|
|
22
|
-
async: "true",
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
navigation: {
|
|
28
|
-
BEGIN: "FLOW_1",
|
|
29
|
-
FLOW_1: {
|
|
30
|
-
startState: "VIEW_1",
|
|
31
|
-
VIEW_1: {
|
|
32
|
-
state_type: "VIEW",
|
|
33
|
-
ref: "my-view",
|
|
34
|
-
transitions: {},
|
|
35
37
|
},
|
|
36
38
|
},
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
+
};
|
|
39
40
|
|
|
40
|
-
const asyncNodeTest = async (resolvedValue: any) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const asyncNodeTest = async (resolvedValue: any) => {
|
|
42
|
+
const plugin = new AsyncNodePlugin({
|
|
43
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
44
|
+
});
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
return new Promise((resolve) => {
|
|
49
|
-
deferredResolve = resolve; // Promise would be resolved only once
|
|
50
|
-
});
|
|
51
|
-
});
|
|
48
|
+
let updateContent: any;
|
|
52
49
|
|
|
53
|
-
|
|
50
|
+
plugin.hooks.onAsyncNode.tap(
|
|
51
|
+
"test",
|
|
52
|
+
async (node: Node.Async, update: (content: any) => void) => {
|
|
53
|
+
const result = new Promise((resolve) => {
|
|
54
|
+
deferredResolve = resolve; // Promise would be resolved only once
|
|
55
|
+
});
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
updateContent = update;
|
|
58
|
+
// Return the result to follow the same mechanism as before
|
|
59
|
+
return result;
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
let updateNumber = 0;
|
|
64
|
+
|
|
65
|
+
const player = new Player({ plugins: [plugin] });
|
|
56
66
|
|
|
57
|
-
|
|
67
|
+
let viewInstance: ViewInstance | undefined;
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
70
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
71
|
+
viewInstance = view;
|
|
72
|
+
view.hooks.onUpdate.tap("async-node-test", () => {
|
|
73
|
+
updateNumber++;
|
|
74
|
+
});
|
|
64
75
|
});
|
|
65
76
|
});
|
|
66
|
-
});
|
|
67
77
|
|
|
68
|
-
|
|
78
|
+
player.start(basicFRFWithActions as any);
|
|
69
79
|
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
81
|
+
.currentView?.lastUpdate;
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
expect(view).toBeDefined();
|
|
84
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
85
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
76
86
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
await waitFor(() => {
|
|
88
|
+
expect(deferredResolve).toBeDefined();
|
|
89
|
+
});
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
// Consumer responds with null/undefined
|
|
92
|
+
if (deferredResolve) {
|
|
93
|
+
deferredResolve(resolvedValue);
|
|
94
|
+
}
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
await waitFor(() => {
|
|
97
|
+
expect(updateNumber).toBe(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
101
|
+
?.lastUpdate;
|
|
102
|
+
|
|
103
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
104
|
+
expect(view?.actions.length).toBe(1);
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
// Consumer responds with null/undefined
|
|
107
|
+
if (deferredResolve) {
|
|
108
|
+
updateContent(resolvedValue);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//Even after an update, the view should not change as we are deleting the resolved node if there is no view update
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(updateNumber).toBe(1);
|
|
114
|
+
});
|
|
92
115
|
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
117
|
+
?.lastUpdate;
|
|
95
118
|
|
|
96
|
-
|
|
119
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
120
|
+
expect(view?.actions.length).toBe(1);
|
|
121
|
+
};
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
test("should return current node view when the resolved node is null", async () => {
|
|
124
|
+
await asyncNodeTest(null);
|
|
100
125
|
});
|
|
101
126
|
|
|
102
|
-
view
|
|
103
|
-
|
|
127
|
+
test("should return current node view when the resolved node is undefined", async () => {
|
|
128
|
+
await asyncNodeTest(undefined);
|
|
129
|
+
});
|
|
104
130
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
131
|
+
test("can handle multiple updates through callback mechanism", async () => {
|
|
132
|
+
const plugin = new AsyncNodePlugin({
|
|
133
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
134
|
+
});
|
|
108
135
|
|
|
109
|
-
|
|
110
|
-
await asyncNodeTest(null);
|
|
111
|
-
});
|
|
136
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
112
137
|
|
|
113
|
-
|
|
114
|
-
await asyncNodeTest(undefined);
|
|
115
|
-
});
|
|
138
|
+
let updateContent: any;
|
|
116
139
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
140
|
+
plugin.hooks.onAsyncNode.tap(
|
|
141
|
+
"test",
|
|
142
|
+
async (node: Node.Async, update: (content: any) => void) => {
|
|
143
|
+
const result = new Promise((resolve) => {
|
|
144
|
+
deferredResolve = resolve; // Promise would be resolved only once
|
|
145
|
+
});
|
|
121
146
|
|
|
122
|
-
|
|
147
|
+
updateContent = update;
|
|
148
|
+
// Return the result to follow the same mechanism as before
|
|
149
|
+
return result;
|
|
150
|
+
},
|
|
151
|
+
);
|
|
123
152
|
|
|
124
|
-
|
|
125
|
-
return new Promise((resolve) => {
|
|
126
|
-
deferredResolve = resolve;
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
let updateNumber = 0;
|
|
153
|
+
let updateNumber = 0;
|
|
130
154
|
|
|
131
|
-
|
|
155
|
+
const player = new Player({ plugins: [plugin] });
|
|
132
156
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
157
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
158
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
159
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
160
|
+
updateNumber++;
|
|
161
|
+
});
|
|
137
162
|
});
|
|
138
163
|
});
|
|
139
|
-
});
|
|
140
164
|
|
|
141
|
-
|
|
165
|
+
player.start(basicFRFWithActions as any);
|
|
142
166
|
|
|
143
|
-
|
|
144
|
-
|
|
167
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
168
|
+
.currentView?.lastUpdate;
|
|
145
169
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
expect(view?.actions[1]).toBeUndefined();
|
|
149
|
-
expect(updateNumber).toBe(1);
|
|
170
|
+
expect(view).toBeDefined();
|
|
171
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
150
172
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
173
|
+
await waitFor(() => {
|
|
174
|
+
expect(updateNumber).toBe(1);
|
|
175
|
+
expect(deferredResolve).toBeDefined();
|
|
176
|
+
});
|
|
154
177
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
178
|
+
if (deferredResolve) {
|
|
179
|
+
deferredResolve({
|
|
180
|
+
asset: {
|
|
181
|
+
id: "next-label-action",
|
|
182
|
+
type: "action",
|
|
183
|
+
value: "dummy value",
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
await waitFor(() => {
|
|
189
|
+
expect(updateNumber).toBe(2);
|
|
162
190
|
});
|
|
163
|
-
}
|
|
164
191
|
|
|
165
|
-
|
|
192
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
193
|
+
?.lastUpdate;
|
|
194
|
+
|
|
195
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
196
|
+
expect(view?.actions[1].asset.type).toBe("action");
|
|
166
197
|
expect(updateNumber).toBe(2);
|
|
167
|
-
});
|
|
168
198
|
|
|
169
|
-
|
|
170
|
-
|
|
199
|
+
if (deferredResolve) {
|
|
200
|
+
updateContent(null);
|
|
201
|
+
}
|
|
171
202
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
});
|
|
203
|
+
await waitFor(() => {
|
|
204
|
+
expect(updateNumber).toBe(3);
|
|
205
|
+
});
|
|
175
206
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
plugins: [new AsyncNodePluginPlugin()],
|
|
179
|
-
});
|
|
207
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
208
|
+
?.lastUpdate;
|
|
180
209
|
|
|
181
|
-
|
|
210
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
211
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
212
|
+
});
|
|
182
213
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
214
|
+
test("replaces async nodes with provided node", async () => {
|
|
215
|
+
const plugin = new AsyncNodePlugin({
|
|
216
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
186
217
|
});
|
|
187
|
-
});
|
|
188
218
|
|
|
189
|
-
|
|
219
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
220
|
+
|
|
221
|
+
plugin.hooks.onAsyncNode.tap("test", async (node: Node.Async) => {
|
|
222
|
+
return new Promise((resolve) => {
|
|
223
|
+
deferredResolve = resolve;
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
let updateNumber = 0;
|
|
190
227
|
|
|
191
|
-
|
|
228
|
+
const player = new Player({ plugins: [plugin] });
|
|
192
229
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
230
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
231
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
232
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
233
|
+
updateNumber++;
|
|
234
|
+
});
|
|
197
235
|
});
|
|
198
236
|
});
|
|
199
|
-
});
|
|
200
237
|
|
|
201
|
-
|
|
238
|
+
player.start(basicFRFWithActions as any);
|
|
202
239
|
|
|
203
|
-
|
|
204
|
-
|
|
240
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
241
|
+
.currentView?.lastUpdate;
|
|
205
242
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
243
|
+
expect(view).toBeDefined();
|
|
244
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
245
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
246
|
+
expect(updateNumber).toBe(1);
|
|
209
247
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
248
|
+
await waitFor(() => {
|
|
249
|
+
expect(deferredResolve).toBeDefined();
|
|
250
|
+
});
|
|
213
251
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
{
|
|
252
|
+
if (deferredResolve) {
|
|
253
|
+
deferredResolve({
|
|
217
254
|
asset: {
|
|
218
|
-
id: "
|
|
219
|
-
type: "
|
|
220
|
-
value: "
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
asset: {
|
|
225
|
-
id: "value-2",
|
|
226
|
-
type: "text",
|
|
227
|
-
value: "2nd value in the multinode",
|
|
255
|
+
id: "next-label-action",
|
|
256
|
+
type: "action",
|
|
257
|
+
value: "dummy value",
|
|
228
258
|
},
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
await waitFor(() => {
|
|
234
|
-
expect(updateNumber).toBe(2);
|
|
235
|
-
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
236
261
|
|
|
237
|
-
|
|
238
|
-
|
|
262
|
+
await waitFor(() => {
|
|
263
|
+
expect(updateNumber).toBe(2);
|
|
264
|
+
});
|
|
239
265
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
expect(view?.actions[2].asset.type).toBe("text");
|
|
243
|
-
});
|
|
266
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
267
|
+
?.lastUpdate;
|
|
244
268
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
plugins: [new AsyncNodePluginPlugin()],
|
|
269
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
270
|
+
expect(view?.actions[1].asset.type).toBe("action");
|
|
248
271
|
});
|
|
249
272
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return new Promise((resolve) => {
|
|
254
|
-
deferredResolve = resolve;
|
|
273
|
+
test("replaces async nodes with multi node", async () => {
|
|
274
|
+
const plugin = new AsyncNodePlugin({
|
|
275
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
255
276
|
});
|
|
256
|
-
});
|
|
257
|
-
let updateNumber = 0;
|
|
258
277
|
|
|
259
|
-
|
|
278
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
260
279
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
updateNumber++;
|
|
280
|
+
plugin.hooks.onAsyncNode.tap("test", async (node) => {
|
|
281
|
+
return new Promise((resolve) => {
|
|
282
|
+
deferredResolve = resolve;
|
|
265
283
|
});
|
|
266
284
|
});
|
|
267
|
-
});
|
|
268
285
|
|
|
269
|
-
|
|
286
|
+
let updateNumber = 0;
|
|
287
|
+
|
|
288
|
+
const player = new Player({ plugins: [plugin] });
|
|
289
|
+
|
|
290
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
291
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
292
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
293
|
+
updateNumber++;
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|
|
270
297
|
|
|
271
|
-
|
|
272
|
-
?.lastUpdate;
|
|
298
|
+
player.start(basicFRFWithActions as any);
|
|
273
299
|
|
|
274
|
-
|
|
275
|
-
|
|
300
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
301
|
+
.currentView?.lastUpdate;
|
|
276
302
|
|
|
277
|
-
|
|
303
|
+
expect(view).toBeDefined();
|
|
304
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
278
305
|
expect(updateNumber).toBe(1);
|
|
279
|
-
expect(deferredResolve).toBeDefined();
|
|
280
|
-
});
|
|
281
306
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
307
|
+
await waitFor(() => {
|
|
308
|
+
expect(deferredResolve).toBeDefined();
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
if (deferredResolve) {
|
|
312
|
+
deferredResolve([
|
|
313
|
+
{
|
|
314
|
+
asset: {
|
|
315
|
+
id: "value-1",
|
|
316
|
+
type: "text",
|
|
317
|
+
value: "1st value in the multinode",
|
|
318
|
+
},
|
|
289
319
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
320
|
+
{
|
|
321
|
+
asset: {
|
|
322
|
+
id: "value-2",
|
|
323
|
+
type: "text",
|
|
324
|
+
value: "2nd value in the multinode",
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
]);
|
|
328
|
+
}
|
|
297
329
|
|
|
298
|
-
|
|
299
|
-
|
|
330
|
+
await waitFor(() => {
|
|
331
|
+
expect(updateNumber).toBe(2);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
335
|
+
?.lastUpdate;
|
|
336
|
+
|
|
337
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
338
|
+
expect(view?.actions[1].asset.type).toBe("text");
|
|
339
|
+
expect(view?.actions[2].asset.type).toBe("text");
|
|
300
340
|
});
|
|
301
341
|
|
|
302
|
-
|
|
303
|
-
|
|
342
|
+
test("replaces async nodes with chained multiNodes", async () => {
|
|
343
|
+
const plugin = new AsyncNodePlugin({
|
|
344
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
345
|
+
});
|
|
304
346
|
|
|
305
|
-
|
|
306
|
-
expect(view?.actions[1].asset.type).toBe("text");
|
|
307
|
-
expect(view?.actions[2]).toBeUndefined();
|
|
308
|
-
expect(updateNumber).toBe(2);
|
|
347
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
309
348
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
349
|
+
plugin.hooks.onAsyncNode.tap("test", async (node: Node.Async) => {
|
|
350
|
+
return new Promise((resolve) => {
|
|
351
|
+
deferredResolve = resolve;
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
let updateNumber = 0;
|
|
355
|
+
|
|
356
|
+
const player = new Player({ plugins: [plugin] });
|
|
357
|
+
|
|
358
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
359
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
360
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
361
|
+
updateNumber++;
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
player.start(basicFRFWithActions as any);
|
|
367
|
+
|
|
368
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
369
|
+
.currentView?.lastUpdate;
|
|
370
|
+
|
|
371
|
+
expect(view).toBeDefined();
|
|
372
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
373
|
+
|
|
374
|
+
await waitFor(() => {
|
|
375
|
+
expect(updateNumber).toBe(1);
|
|
376
|
+
expect(deferredResolve).toBeDefined();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
if (deferredResolve) {
|
|
380
|
+
deferredResolve([
|
|
381
|
+
{
|
|
382
|
+
asset: {
|
|
383
|
+
id: "value-1",
|
|
384
|
+
type: "text",
|
|
385
|
+
value: "1st value in the multinode",
|
|
386
|
+
},
|
|
317
387
|
},
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
id: "value-3",
|
|
322
|
-
type: "text",
|
|
323
|
-
value: "3rd value in the multinode",
|
|
388
|
+
{
|
|
389
|
+
id: "another-async",
|
|
390
|
+
async: true,
|
|
324
391
|
},
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
392
|
+
]);
|
|
393
|
+
}
|
|
328
394
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
395
|
+
await waitFor(() => {
|
|
396
|
+
expect(updateNumber).toBe(2);
|
|
397
|
+
});
|
|
332
398
|
|
|
333
|
-
|
|
334
|
-
|
|
399
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
400
|
+
?.lastUpdate;
|
|
335
401
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
402
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
403
|
+
expect(view?.actions[1].asset.type).toBe("text");
|
|
404
|
+
expect(view?.actions[2]).toBeUndefined();
|
|
405
|
+
expect(updateNumber).toBe(2);
|
|
406
|
+
|
|
407
|
+
if (deferredResolve) {
|
|
408
|
+
deferredResolve([
|
|
409
|
+
{
|
|
410
|
+
asset: {
|
|
411
|
+
id: "value-2",
|
|
412
|
+
type: "text",
|
|
413
|
+
value: "2nd value in the multinode",
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
asset: {
|
|
418
|
+
id: "value-3",
|
|
419
|
+
type: "text",
|
|
420
|
+
value: "3rd value in the multinode",
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
]);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
await waitFor(() => {
|
|
427
|
+
expect(updateNumber).toBe(3);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
431
|
+
?.lastUpdate;
|
|
341
432
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
433
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
434
|
+
expect(view?.actions[1].asset.type).toBe("text");
|
|
435
|
+
expect(view?.actions[2].asset.type).toBe("text");
|
|
436
|
+
expect(view?.actions[3].asset.type).toBe("text");
|
|
345
437
|
});
|
|
346
438
|
|
|
347
|
-
|
|
439
|
+
test("replaces async nodes with chained multiNodes singular", async () => {
|
|
440
|
+
const plugin = new AsyncNodePlugin({
|
|
441
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
348
445
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
446
|
+
plugin.hooks.onAsyncNode.tap("test", async (node: Node.Async) => {
|
|
447
|
+
return new Promise((resolve) => {
|
|
448
|
+
deferredResolve = resolve;
|
|
449
|
+
});
|
|
352
450
|
});
|
|
353
|
-
|
|
354
|
-
let updateNumber = 0;
|
|
451
|
+
let updateNumber = 0;
|
|
355
452
|
|
|
356
|
-
|
|
453
|
+
const player = new Player({ plugins: [plugin] });
|
|
357
454
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
455
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
456
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
457
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
458
|
+
updateNumber++;
|
|
459
|
+
});
|
|
362
460
|
});
|
|
363
461
|
});
|
|
364
|
-
});
|
|
365
462
|
|
|
366
|
-
|
|
463
|
+
player.start(basicFRFWithActions as any);
|
|
367
464
|
|
|
368
|
-
|
|
369
|
-
|
|
465
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
466
|
+
.currentView?.lastUpdate;
|
|
370
467
|
|
|
371
|
-
|
|
372
|
-
|
|
468
|
+
expect(view).toBeDefined();
|
|
469
|
+
expect(view?.actions[1]).toBeUndefined();
|
|
373
470
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
471
|
+
await waitFor(() => {
|
|
472
|
+
expect(updateNumber).toBe(1);
|
|
473
|
+
expect(deferredResolve).toBeDefined();
|
|
474
|
+
});
|
|
378
475
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
476
|
+
if (deferredResolve) {
|
|
477
|
+
deferredResolve([
|
|
478
|
+
{
|
|
479
|
+
asset: {
|
|
480
|
+
id: "value-1",
|
|
481
|
+
type: "text",
|
|
482
|
+
value: "1st value in the multinode",
|
|
483
|
+
},
|
|
386
484
|
},
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
485
|
+
{
|
|
486
|
+
id: "another-async",
|
|
487
|
+
async: true,
|
|
488
|
+
},
|
|
489
|
+
]);
|
|
490
|
+
}
|
|
394
491
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
492
|
+
await waitFor(() => {
|
|
493
|
+
expect(updateNumber).toBe(2);
|
|
494
|
+
});
|
|
398
495
|
|
|
399
|
-
|
|
400
|
-
|
|
496
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
497
|
+
?.lastUpdate;
|
|
401
498
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
499
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
500
|
+
expect(view?.actions[1].asset.type).toBe("text");
|
|
501
|
+
expect(view?.actions[2]).toBeUndefined();
|
|
405
502
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
503
|
+
if (deferredResolve) {
|
|
504
|
+
deferredResolve({
|
|
505
|
+
asset: {
|
|
506
|
+
id: "value-2",
|
|
507
|
+
type: "text",
|
|
508
|
+
value: "2nd value in the multinode",
|
|
509
|
+
},
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
await waitFor(() => {
|
|
514
|
+
expect(updateNumber).toBe(3);
|
|
413
515
|
});
|
|
414
|
-
}
|
|
415
516
|
|
|
416
|
-
|
|
417
|
-
|
|
517
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
518
|
+
?.lastUpdate;
|
|
519
|
+
|
|
520
|
+
expect(view?.actions[0].asset.type).toBe("action");
|
|
521
|
+
expect(view?.actions[1].asset.type).toBe("text");
|
|
522
|
+
expect(view?.actions[2].asset.type).toBe("text");
|
|
418
523
|
});
|
|
419
524
|
|
|
420
|
-
|
|
421
|
-
|
|
525
|
+
test("should call onAsyncNode hook when async node is encountered", async () => {
|
|
526
|
+
const plugin = new AsyncNodePlugin({
|
|
527
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
528
|
+
});
|
|
422
529
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
530
|
+
let localNode: Node.Async;
|
|
531
|
+
plugin.hooks.onAsyncNode.tap("test", async (node: Node.Async) => {
|
|
532
|
+
if (node !== null) {
|
|
533
|
+
// assigns node value to a local variable
|
|
534
|
+
localNode = node;
|
|
535
|
+
}
|
|
427
536
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
537
|
+
return new Promise((resolve) => {
|
|
538
|
+
resolve("Promise resolved");
|
|
539
|
+
});
|
|
540
|
+
});
|
|
432
541
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// assigns node value to a local variable
|
|
437
|
-
localNode = node;
|
|
438
|
-
}
|
|
542
|
+
const player = new Player({ plugins: [plugin] });
|
|
543
|
+
|
|
544
|
+
player.start(basicFRFWithActions as any);
|
|
439
545
|
|
|
440
|
-
|
|
441
|
-
|
|
546
|
+
await waitFor(() => {
|
|
547
|
+
expect(localNode.id).toStrictEqual("nodeId");
|
|
548
|
+
expect(localNode.type).toStrictEqual("async");
|
|
442
549
|
});
|
|
443
550
|
});
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
describe("parser", () => {
|
|
554
|
+
test("missing node-id parent async node", async () => {
|
|
555
|
+
const parser = new Parser();
|
|
556
|
+
new AsyncNodePluginPlugin().applyParser(parser);
|
|
557
|
+
const parsedAST = parser.parseObject({ async: "true" });
|
|
444
558
|
|
|
445
|
-
|
|
559
|
+
expect(parsedAST).toStrictEqual(null);
|
|
560
|
+
});
|
|
446
561
|
|
|
447
|
-
|
|
562
|
+
test("missing node-id child async node", async () => {
|
|
563
|
+
const parser = new Parser();
|
|
564
|
+
new AsyncNodePluginPlugin().applyParser(parser);
|
|
565
|
+
const parsedAST = parser.parseObject({ fields: { async: "true" } });
|
|
448
566
|
|
|
449
|
-
|
|
450
|
-
expect(localNode.id).toStrictEqual("nodeId");
|
|
451
|
-
expect(localNode.type).toStrictEqual("async");
|
|
567
|
+
expect(parsedAST).toStrictEqual(null);
|
|
452
568
|
});
|
|
453
569
|
});
|