@player-ui/async-node-plugin 0.8.0-next.4 → 0.8.0-next.5

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