@yuneta/gobj-ui 7.25.13 → 7.25.15

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.
@@ -5,7 +5,7 @@
5
5
  * through the real gclasses (C_YUI_SHELL, C_YUI_TREEDB_TOPICS) on a
6
6
  * document double. The helper (form_writes_in_flight.js) was tested
7
7
  * and right; what failed was that two hosts never called the action
8
- * that uses it (M8 of the 2026-09-23 review), which no helper test
8
+ * that uses it, which no helper test
9
9
  * can see.
10
10
  *
11
11
  * Copyright (c) 2026, ArtGins.
@@ -30,6 +30,7 @@ const {register_c_yui_treedb_topics} = await import("./c_yui_treedb_topics.js");
30
30
 
31
31
  const logged = [];
32
32
  const answers = []; /* what the fake forms were told */
33
+ const loaded = []; /* the rows each fake form was loaded with */
33
34
  const commands = []; /* what the fake transport was asked */
34
35
 
35
36
  /*
@@ -57,6 +58,12 @@ function ac_form_answer(gobj, event, kw, src)
57
58
  return 0;
58
59
  }
59
60
 
61
+ function ac_form_load(gobj, event, kw, src)
62
+ {
63
+ loaded.push({topic: gobj.priv_topic, rows: kw});
64
+ return 0;
65
+ }
66
+
60
67
  let yuno = null;
61
68
  let remote = null;
62
69
 
@@ -76,10 +83,11 @@ beforeAll(() => {
76
83
  );
77
84
  gclass_create(
78
85
  "C_YUI_TREEDB_TOPIC_WITH_FORM",
79
- [["EV_WRITE_DONE", 0], ["EV_WRITE_REFUSED", 0]],
86
+ [["EV_WRITE_DONE", 0], ["EV_WRITE_REFUSED", 0], ["EV_LOAD_NODES", 0]],
80
87
  [["ST_IDLE", [
81
88
  ["EV_WRITE_DONE", ac_form_answer, null],
82
- ["EV_WRITE_REFUSED", ac_form_answer, null]
89
+ ["EV_WRITE_REFUSED", ac_form_answer, null],
90
+ ["EV_LOAD_NODES", ac_form_load, null]
83
91
  ]]],
84
92
  {},
85
93
  0,
@@ -115,6 +123,7 @@ beforeEach(() => {
115
123
  logged.length = 0;
116
124
  answers.length = 0;
117
125
  commands.length = 0;
126
+ loaded.length = 0;
118
127
  });
119
128
 
120
129
  function build(name)
@@ -136,7 +145,9 @@ function build(name)
136
145
 
137
146
  const forms = {};
138
147
  for(const topic of ["users", "roles"]) {
139
- forms[topic] = gobj_create(`${name}_form_${topic}`, "C_YUI_TREEDB_TOPIC_WITH_FORM",
148
+ /* Named as the view names its forms: the answer of a `nodes`
149
+ * finds its table by that name. */
150
+ forms[topic] = gobj_create(`${name}_topics?${topic}`, "C_YUI_TREEDB_TOPIC_WITH_FORM",
140
151
  {topic_name: topic}, topics);
141
152
  forms[topic].priv_topic = topic;
142
153
  }
@@ -277,13 +288,12 @@ describe("a write cut by the drop does not reload out of session", () => {
277
288
  gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: false}, topics);
278
289
  expect(nodes_asked()).toEqual([]);
279
290
 
280
- /* The reconnect reloads what the drop left unknown -- once, though
281
- * two edges report it. */
291
+ /* The reconnect reads every open table -- once, though two edges
292
+ * report it. */
282
293
  gobj_change_state(remote, "ST_SESSION");
283
294
  gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
284
- yui_shell_set_connection_state(shell, false);
285
295
  yui_shell_set_connection_state(shell, true);
286
- expect(nodes_asked()).toEqual(["users"]);
296
+ expect(nodes_asked().sort()).toEqual(["roles", "users"]);
287
297
  expect(errors()).toEqual([]);
288
298
  });
289
299
 
@@ -303,7 +313,7 @@ describe("a write cut by the drop does not reload out of session", () => {
303
313
 
304
314
  gobj_change_state(remote, "ST_SESSION");
305
315
  yui_shell_set_connection_state(shell, true);
306
- expect(nodes_asked()).toEqual(["users"]);
316
+ expect(nodes_asked().sort()).toEqual(["roles", "users"]);
307
317
  expect(errors()).toEqual([]);
308
318
  });
309
319
 
@@ -322,20 +332,78 @@ describe("a write cut by the drop does not reload out of session", () => {
322
332
 
323
333
  gobj_change_state(remote, "ST_SESSION");
324
334
  gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
325
- expect(nodes_asked()).toEqual(["roles"]);
335
+ expect(nodes_asked().sort()).toEqual(["roles", "users"]);
326
336
  expect(errors().filter((m) => m.includes("not in session"))).toEqual([]);
327
337
  });
328
338
 
329
- test("a write refused IN session reloads its topic at once, and only then", () => {
339
+ test("a write refused IN session reloads its topic at once", () => {
330
340
  const {shell, topics} = build("t9");
331
341
  yui_shell_set_connection_state(shell, true);
332
342
  gobj_send_event(topics, "EV_UPDATE_FIELD",
333
343
  {topic_name: "users", id: "x", field: "name", value: "typed"}, topics);
334
344
  gobj_send_event(topics, "EV_MT_COMMAND_ANSWER", failed_write("users", 0), remote);
335
345
  expect(nodes_asked()).toEqual(["users"]);
346
+ });
347
+ });
336
348
 
349
+ /*
350
+ * The answer of a `nodes`, the way C_IEVENT_CLI delivers it.
351
+ */
352
+ function nodes_answer_of(topic_name, rows)
353
+ {
354
+ return {result: 0, comment: "", data: rows, __md_iev__: {
355
+ command_stack: [{command: "nodes", kw: {topic_name: topic_name}}]
356
+ }};
357
+ }
358
+
359
+ describe("what the drop hid is read again on the reconnect", () => {
360
+
361
+ test("a node created during the drop is in its table after the reconnect", () => {
362
+ const {shell, topics} = build("t10");
363
+ yui_shell_set_connection_state(shell, true);
364
+
365
+ /* No write in flight: the session just drops. While it is down,
366
+ * another writer creates a user; its EV_TREEDB_NODE_CREATED is
367
+ * published to nobody. */
368
+ gobj_change_state(remote, "ST_DISCONNECTED");
337
369
  gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: false}, topics);
370
+ yui_shell_set_connection_state(shell, false);
371
+ expect(nodes_asked()).toEqual([]);
372
+
373
+ gobj_change_state(remote, "ST_SESSION");
338
374
  gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
339
- expect(nodes_asked()).toEqual(["users"]);
375
+ yui_shell_set_connection_state(shell, true);
376
+
377
+ /* Every open table is read once, though two edges said "up". */
378
+ expect(nodes_asked().sort()).toEqual(["roles", "users"]);
379
+
380
+ gobj_send_event(topics, "EV_MT_COMMAND_ANSWER",
381
+ nodes_answer_of("users", [{id: "x"}, {id: "created_during_the_drop"}]), remote);
382
+ expect(loaded).toEqual([
383
+ {topic: "users", rows: [{id: "x"}, {id: "created_during_the_drop"}]}
384
+ ]);
385
+ expect(errors()).toEqual([]);
386
+ });
387
+
388
+ test("an 'up' with no drop before it reads nothing", () => {
389
+ const {shell, topics} = build("t11");
390
+ yui_shell_set_connection_state(shell, true);
391
+ gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
392
+ expect(nodes_asked()).toEqual([]);
393
+ });
394
+
395
+ test("an edge that says 'up' before the transport is in session waits", () => {
396
+ const {shell, topics} = build("t12");
397
+ yui_shell_set_connection_state(shell, true);
398
+ gobj_change_state(remote, "ST_DISCONNECTED");
399
+ yui_shell_set_connection_state(shell, false);
400
+
401
+ yui_shell_set_connection_state(shell, true);
402
+ expect(nodes_asked()).toEqual([]);
403
+ expect(errors().filter((m) => m.includes("not in session"))).toEqual([]);
404
+
405
+ gobj_change_state(remote, "ST_SESSION");
406
+ gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
407
+ expect(nodes_asked().sort()).toEqual(["roles", "users"]);
340
408
  });
341
409
  });
@@ -115,7 +115,7 @@ describe("is_hook_size", () => {
115
115
  * The children of a hook as the NODE EVENTS deliver them: `{id,
116
116
  * topic_name}`, with no hook_name. Not taken for a reference, their
117
117
  * topic_name -- the same word on every row -- was a wildcard for every
118
- * row that had received an UPDATED (M30 of the 2026-09-21 review).
118
+ * row that had received an UPDATED.
119
119
  */
120
120
  describe("a hook's children as the node events deliver them", () => {
121
121
  const row = {id: "w1", devices: [{id: "d7", topic_name: "devices"}]};
@@ -59,7 +59,7 @@ describe("reading and dropping the selection", () => {
59
59
  * A table as the delete of the treedb topic table meets it AFTER a
60
60
  * confirmation: rows came and went while the dialog was open. A position
61
61
  * names whatever row sits there now; an id names the row the question named
62
- * (the regression of d60ec78, A6 of the 2026-09-21 review).
62
+ * (the regression of d60ec78).
63
63
  */
64
64
  function fake_table(rows, index)
65
65
  {