@hydranium/conformance 1.0.0-next.254 → 1.0.0-next.255

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/README.md CHANGED
@@ -57,7 +57,9 @@ Each function takes `connect` and `languages`:
57
57
 
58
58
  The GLSP slice is generic over your action type and takes a `GlspFixture` per
59
59
  diagram type. The fixture builds your native actions, and the kit matches the
60
- responses by `kind`.
60
+ responses by `kind`. A create check also waits for the operation's receipt,
61
+ the `setDirtyState` with reason `'operation'` GLSP sends for an operation that
62
+ ran, so the session must declare `setDirtyState`.
61
63
 
62
64
  To check a deployed GLSP server rather than one built in your test process,
63
65
  return `connectGlspSocketDriver({ port, diagramType, clientActionKinds })` from
@@ -20,7 +20,12 @@ export interface GlspConformanceDriver<TAction> extends Harness {
20
20
  start(): Promise<void>;
21
21
  /** Send an action to the server. Fire-and-forget (GLSP `process` is `void`). */
22
22
  dispatch(action: TAction): void;
23
- /** Resolve with the next captured action whose `kind` matches; reject on timeout. */
23
+ /**
24
+ * Resolve with the next action whose `kind` matches and that arrived after
25
+ * the last {@link dispatch}, or since `start` before any; reject on timeout.
26
+ * Only after the dispatch, so an action an earlier step sent cannot pass for
27
+ * the answer to this one.
28
+ */
24
29
  nextAction<T extends TAction = TAction>(kind: string, timeoutMs?: number): Promise<T>;
25
30
  }
26
31
  /**
@@ -43,7 +48,18 @@ export interface GlspCreateOperationSpec<TAction, TDriver extends GlspConformanc
43
48
  * loaded.
44
49
  */
45
50
  readonly action: (driver: TDriver) => TAction;
46
- /** The action kind the server settles the operation with (e.g. a re-`RequestBounds` for client-laid-out diagrams). */
51
+ /**
52
+ * The action kind the server settles the operation with (e.g. a
53
+ * re-`RequestBounds` for client-laid-out diagrams).
54
+ *
55
+ * The kit also waits for the operation's receipt: GLSP's
56
+ * `OperationActionHandler` submits every operation that ran with reason
57
+ * `'operation'`, and `ModelSubmissionHandler` ends that submission with a
58
+ * `setDirtyState` carrying it. A declined operation sends none,
59
+ * so an action of this kind from something else, such as a late submission
60
+ * of the load, cannot pass for the operation's. The driver's session must
61
+ * receive `setDirtyState`.
62
+ */
47
63
  readonly expectedResponseKind: string;
48
64
  /**
49
65
  * Returns whether the source model gained the element — the adopter reads its
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/glsp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAoBlF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB,CAAC,OAAO,CAAE,SAAQ,OAAO;IAC5D,uFAAuF;IACvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,qFAAqF;IACrF,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxF;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC;IAC7F;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC9C,sHAAsH;IACtH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC;IACjF;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,OAAO,CAAC;IACrC,oGAAoG;IACpG,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,6HAA6H;IAC7H,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;IACzD,oEAAoE;IACpE,QAAQ,CAAC,eAAe,CAAC,EAAE,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;CACvE;AAED,wCAAwC;AACxC,MAAM,WAAW,sBAAsB,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC;IAC5F;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC,EACpF,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,GACjD,gBAAgB,EAAE,CAoEpB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/glsp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAsBlF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB,CAAC,OAAO,CAAE,SAAQ,OAAO;IAC5D,uFAAuF;IACvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxF;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC;IAC7F;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC;IACjF;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,OAAO,CAAC;IACrC,oGAAoG;IACpG,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,6HAA6H;IAC7H,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;IACzD,oEAAoE;IACpE,QAAQ,CAAC,eAAe,CAAC,EAAE,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;CACvE;AAED,wCAAwC;AACxC,MAAM,WAAW,sBAAsB,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC;IAC5F;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC/B;AAoCD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,SAAS,qBAAqB,CAAC,OAAO,CAAC,EACpF,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,GACjD,gBAAgB,EAAE,CAqEpB"}
package/lib/glsp/index.js CHANGED
@@ -11,7 +11,9 @@
11
11
  * head, generic over the adopter's action type `TAction`. The kit imports NO
12
12
  * `@eclipse-glsp/*` types: the FIXTURE supplies the native actions
13
13
  * (`requestModel()`, `createOperation.action()`) and the kit matches responses
14
- * by `kind` (a `string`) via the driver's `nextAction`.
14
+ * by `kind` (a `string`) via the driver's `nextAction`. The one field it reads
15
+ * beyond `kind` is the `reason` of the `setDirtyState` that is an operation's
16
+ * receipt.
15
17
  *
16
18
  * The driver port (`GlspConformanceDriver<TAction>`) is the minimal
17
19
  * `start` / `dispatch` / `nextAction` surface that `@hydranium/glsp-server/
@@ -23,6 +25,34 @@
23
25
  * its harness.
24
26
  */
25
27
  import assert from 'node:assert/strict';
28
+ /** GLSP's `SetDirtyStateAction.KIND`, named here because the kit imports no GLSP type. */
29
+ const SET_DIRTY_STATE_KIND = 'setDirtyState';
30
+ /** The reason GLSP's `OperationActionHandler` submits an operation that ran with, which its dirty state carries. */
31
+ const OPERATION_REASON = 'operation';
32
+ function isOperationReceipt(action) {
33
+ return typeof action === 'object' && action !== null && 'reason' in action && action.reason === OPERATION_REASON;
34
+ }
35
+ /**
36
+ * Resolve once the operation's receipt arrives, passing over a dirty state
37
+ * with any other reason. Rejects with the wait's own failure, which may be a
38
+ * closed connection rather than a missing receipt.
39
+ */
40
+ async function nextOperationReceipt(driver) {
41
+ for (;;) {
42
+ let dirtyState;
43
+ try {
44
+ dirtyState = await driver.nextAction(SET_DIRTY_STATE_KIND);
45
+ }
46
+ catch (error) {
47
+ const reason = error instanceof Error ? error.message : String(error);
48
+ throw new Error(`Waiting for the operation's receipt, a ${SET_DIRTY_STATE_KIND} with reason '${OPERATION_REASON}', failed: ${reason}. ` +
49
+ `If none arrived in time, either no operation ran or the session does not declare ${SET_DIRTY_STATE_KIND}.`, { cause: error });
50
+ }
51
+ if (isOperationReceipt(dirtyState)) {
52
+ return;
53
+ }
54
+ }
55
+ }
26
56
  /**
27
57
  * Build the GLSP check battery — per diagram type: `start()` resolves;
28
58
  * `RequestModel` responds with the expected kind (+ optional `expectResponse`
@@ -78,6 +108,7 @@ export function buildGlspChecks(options) {
78
108
  driver.dispatch(diagram.requestModel());
79
109
  await driver.nextAction(diagram.expectedResponseKind);
80
110
  driver.dispatch(operation.action(driver));
111
+ await nextOperationReceipt(driver);
81
112
  await driver.nextAction(operation.expectedResponseKind);
82
113
  assert.ok(await operation.expectMutated(driver), 'expectMutated was false — the create operation did not mutate the source model');
83
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/glsp/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/glsp/index.ts"],"names":[],"mappings":"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"}
@@ -38,8 +38,10 @@ export interface GlspSocketDriverOptions<TAction extends {
38
38
  * The client's reply to a received action, sent back to the server, or
39
39
  * `undefined` for none. A server that lays out on the client finishes a
40
40
  * `requestModel` only once its `requestBounds` is answered with
41
- * `computedBounds`, so a load without this stops half way. A throw fails
42
- * every pending and later wait with it.
41
+ * `computedBounds`, so a load without this stops half way. A reply is not a
42
+ * dispatch, as the GLSP client's own is an automatic answer to the server,
43
+ * so it leaves the point `nextAction` matches from where it was. A throw
44
+ * fails every pending and later wait with it.
43
45
  */
44
46
  readonly respond?: (action: TAction) => TAction | undefined;
45
47
  /** Default bound for {@link GlspConformanceDriver.nextAction}, and the bound on the TCP connect and on each `start()` request. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/glsp/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAclF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAMzD,yDAAyD;AACzD,MAAM,WAAW,uBAAuB,CAAC,OAAO,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;IAC3G,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,8FAA8F;IAC9F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;IAC5D,kIAAkI;IAClI,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,mFAAmF;AACnF,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAE,SAAQ,qBAAqB,CAAC,OAAO,CAAC;IAChH,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC3C;AAgBD;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpF,OAAO,EAAE,uBAAuB,CAAC,OAAO,CAAC,GACzC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAuIpC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/glsp/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAclF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAMzD,yDAAyD;AACzD,MAAM,WAAW,uBAAuB,CAAC,OAAO,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;IAC3G,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,8FAA8F;IAC9F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;IAC5D,kIAAkI;IAClI,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,mFAAmF;AACnF,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAE,SAAQ,qBAAqB,CAAC,OAAO,CAAC;IAChH,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC3C;AAgBD;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpF,OAAO,EAAE,uBAAuB,CAAC,OAAO,CAAC,GACzC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAqJpC"}
@@ -47,6 +47,8 @@ export async function connectGlspSocketDriver(options) {
47
47
  }
48
48
  };
49
49
  const consumed = new WeakSet();
50
+ // Where the last dispatch fell in `actions`; a wait matches only from here.
51
+ let dispatchedAt = 0;
50
52
  const waiters = [];
51
53
  // Why no awaited action can arrive any more, once something ended the session.
52
54
  let ended;
@@ -104,9 +106,12 @@ export async function connectGlspSocketDriver(options) {
104
106
  clientActionKinds: options.clientActionKinds
105
107
  }), timeoutMs, 'initializeClientSession');
106
108
  },
107
- dispatch: send,
109
+ dispatch(action) {
110
+ dispatchedAt = actions.length;
111
+ send(action);
112
+ },
108
113
  nextAction(kind, waitMs = timeoutMs) {
109
- const existing = actions.find(action => action.kind === kind && !consumed.has(action));
114
+ const existing = actions.find((action, index) => index >= dispatchedAt && action.kind === kind && !consumed.has(action));
110
115
  if (existing) {
111
116
  consumed.add(existing);
112
117
  return Promise.resolve(existing);
@@ -132,9 +137,16 @@ export async function connectGlspSocketDriver(options) {
132
137
  waiters.splice(at, 1);
133
138
  }
134
139
  // Naming what did arrive tells an operation the server declined
135
- // (a status or nothing at all) apart from a transport that hangs.
136
- const seen = actions.map(action => action.kind).join(', ') || 'nothing';
137
- reject(new Error(`No '${kind}' action within ${waitMs}ms on session ${clientSessionId}; received: ${seen}`));
140
+ // (a status or nothing at all) apart from a transport that hangs,
141
+ // split at the last dispatch, before which no match counts.
142
+ const kindsIn = (from, to) => actions
143
+ .slice(from, to)
144
+ .map(action => action.kind)
145
+ .join(', ') || 'nothing';
146
+ const seen = dispatchedAt === 0
147
+ ? `received: ${kindsIn(0)}`
148
+ : `received before the last dispatch, which a wait does not match: ${kindsIn(0, dispatchedAt)}; since: ${kindsIn(dispatchedAt)}`;
149
+ reject(new Error(`No '${kind}' action within ${waitMs}ms on session ${clientSessionId}; ${seen}`));
138
150
  }, waitMs);
139
151
  waiters.push(waiter);
140
152
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/glsp/node/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/glsp/node/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/conformance",
3
- "version": "1.0.0-next.254",
3
+ "version": "1.0.0-next.255",
4
4
  "description": "Protocol conformance kit (TCK) for hydranium adopters. Per-head slices (/data, /lsp, /glsp) of fixture-parameterized, protocol-only smoke checks an adopter runs against its own server.",
5
5
  "keywords": [
6
6
  "conformance",
@@ -75,7 +75,7 @@
75
75
  "watch": "tsc -b -w --preserveWatchOutput"
76
76
  },
77
77
  "devDependencies": {
78
- "@hydranium/protocol": "1.0.0-next.254",
78
+ "@hydranium/protocol": "1.0.0-next.255",
79
79
  "@jest/globals": "^29.7.0",
80
80
  "@types/jest": "^29.5.12",
81
81
  "esbuild": "^0.28.0",
@@ -86,7 +86,7 @@
86
86
  "vscode-jsonrpc": "9.0.0"
87
87
  },
88
88
  "peerDependencies": {
89
- "@hydranium/protocol": "1.0.0-next.254",
89
+ "@hydranium/protocol": "1.0.0-next.255",
90
90
  "@jest/globals": "^29.0.0",
91
91
  "vitest": "^4.0.0",
92
92
  "vscode-jsonrpc": "^9.0.0"
package/src/glsp/index.ts CHANGED
@@ -12,7 +12,9 @@
12
12
  * head, generic over the adopter's action type `TAction`. The kit imports NO
13
13
  * `@eclipse-glsp/*` types: the FIXTURE supplies the native actions
14
14
  * (`requestModel()`, `createOperation.action()`) and the kit matches responses
15
- * by `kind` (a `string`) via the driver's `nextAction`.
15
+ * by `kind` (a `string`) via the driver's `nextAction`. The one field it reads
16
+ * beyond `kind` is the `reason` of the `setDirtyState` that is an operation's
17
+ * receipt.
16
18
  *
17
19
  * The driver port (`GlspConformanceDriver<TAction>`) is the minimal
18
20
  * `start` / `dispatch` / `nextAction` surface that `@hydranium/glsp-server/
@@ -40,7 +42,12 @@ export interface GlspConformanceDriver<TAction> extends Harness {
40
42
  start(): Promise<void>;
41
43
  /** Send an action to the server. Fire-and-forget (GLSP `process` is `void`). */
42
44
  dispatch(action: TAction): void;
43
- /** Resolve with the next captured action whose `kind` matches; reject on timeout. */
45
+ /**
46
+ * Resolve with the next action whose `kind` matches and that arrived after
47
+ * the last {@link dispatch}, or since `start` before any; reject on timeout.
48
+ * Only after the dispatch, so an action an earlier step sent cannot pass for
49
+ * the answer to this one.
50
+ */
44
51
  nextAction<T extends TAction = TAction>(kind: string, timeoutMs?: number): Promise<T>;
45
52
  }
46
53
 
@@ -64,7 +71,18 @@ export interface GlspCreateOperationSpec<TAction, TDriver extends GlspConformanc
64
71
  * loaded.
65
72
  */
66
73
  readonly action: (driver: TDriver) => TAction;
67
- /** The action kind the server settles the operation with (e.g. a re-`RequestBounds` for client-laid-out diagrams). */
74
+ /**
75
+ * The action kind the server settles the operation with (e.g. a
76
+ * re-`RequestBounds` for client-laid-out diagrams).
77
+ *
78
+ * The kit also waits for the operation's receipt: GLSP's
79
+ * `OperationActionHandler` submits every operation that ran with reason
80
+ * `'operation'`, and `ModelSubmissionHandler` ends that submission with a
81
+ * `setDirtyState` carrying it. A declined operation sends none,
82
+ * so an action of this kind from something else, such as a late submission
83
+ * of the load, cannot pass for the operation's. The driver's session must
84
+ * receive `setDirtyState`.
85
+ */
68
86
  readonly expectedResponseKind: string;
69
87
  /**
70
88
  * Returns whether the source model gained the element — the adopter reads its
@@ -140,6 +158,40 @@ export interface GlspConformanceOptions<TAction, TDriver extends GlspConformance
140
158
  readonly suiteTitle?: string;
141
159
  }
142
160
 
161
+ /** GLSP's `SetDirtyStateAction.KIND`, named here because the kit imports no GLSP type. */
162
+ const SET_DIRTY_STATE_KIND = 'setDirtyState';
163
+
164
+ /** The reason GLSP's `OperationActionHandler` submits an operation that ran with, which its dirty state carries. */
165
+ const OPERATION_REASON = 'operation';
166
+
167
+ function isOperationReceipt(action: unknown): boolean {
168
+ return typeof action === 'object' && action !== null && 'reason' in action && action.reason === OPERATION_REASON;
169
+ }
170
+
171
+ /**
172
+ * Resolve once the operation's receipt arrives, passing over a dirty state
173
+ * with any other reason. Rejects with the wait's own failure, which may be a
174
+ * closed connection rather than a missing receipt.
175
+ */
176
+ async function nextOperationReceipt<TAction>(driver: GlspConformanceDriver<TAction>): Promise<void> {
177
+ for (;;) {
178
+ let dirtyState: TAction;
179
+ try {
180
+ dirtyState = await driver.nextAction(SET_DIRTY_STATE_KIND);
181
+ } catch (error: unknown) {
182
+ const reason = error instanceof Error ? error.message : String(error);
183
+ throw new Error(
184
+ `Waiting for the operation's receipt, a ${SET_DIRTY_STATE_KIND} with reason '${OPERATION_REASON}', failed: ${reason}. ` +
185
+ `If none arrived in time, either no operation ran or the session does not declare ${SET_DIRTY_STATE_KIND}.`,
186
+ { cause: error }
187
+ );
188
+ }
189
+ if (isOperationReceipt(dirtyState)) {
190
+ return;
191
+ }
192
+ }
193
+ }
194
+
143
195
  /**
144
196
  * Build the GLSP check battery — per diagram type: `start()` resolves;
145
197
  * `RequestModel` responds with the expected kind (+ optional `expectResponse`
@@ -199,6 +251,7 @@ export function buildGlspChecks<TAction, TDriver extends GlspConformanceDriver<T
199
251
  driver.dispatch(diagram.requestModel());
200
252
  await driver.nextAction(diagram.expectedResponseKind);
201
253
  driver.dispatch(operation.action(driver));
254
+ await nextOperationReceipt(driver);
202
255
  await driver.nextAction(operation.expectedResponseKind);
203
256
  assert.ok(
204
257
  await operation.expectMutated(driver),
@@ -52,8 +52,10 @@ export interface GlspSocketDriverOptions<TAction extends { readonly kind: string
52
52
  * The client's reply to a received action, sent back to the server, or
53
53
  * `undefined` for none. A server that lays out on the client finishes a
54
54
  * `requestModel` only once its `requestBounds` is answered with
55
- * `computedBounds`, so a load without this stops half way. A throw fails
56
- * every pending and later wait with it.
55
+ * `computedBounds`, so a load without this stops half way. A reply is not a
56
+ * dispatch, as the GLSP client's own is an automatic answer to the server,
57
+ * so it leaves the point `nextAction` matches from where it was. A throw
58
+ * fails every pending and later wait with it.
57
59
  */
58
60
  readonly respond?: (action: TAction) => TAction | undefined;
59
61
  /** Default bound for {@link GlspConformanceDriver.nextAction}, and the bound on the TCP connect and on each `start()` request. */
@@ -103,6 +105,8 @@ export async function connectGlspSocketDriver<TAction extends { readonly kind: s
103
105
  }
104
106
  };
105
107
  const consumed = new WeakSet<TAction>();
108
+ // Where the last dispatch fell in `actions`; a wait matches only from here.
109
+ let dispatchedAt = 0;
106
110
  const waiters: Array<{ readonly kind: string; readonly resolve: (action: TAction) => void; readonly fail: (error: Error) => void }> = [];
107
111
  // Why no awaited action can arrive any more, once something ended the session.
108
112
  let ended: { readonly reason: string; readonly cause?: unknown } | undefined;
@@ -173,10 +177,13 @@ export async function connectGlspSocketDriver<TAction extends { readonly kind: s
173
177
  );
174
178
  },
175
179
 
176
- dispatch: send,
180
+ dispatch(action: TAction): void {
181
+ dispatchedAt = actions.length;
182
+ send(action);
183
+ },
177
184
 
178
185
  nextAction<T extends TAction = TAction>(kind: string, waitMs = timeoutMs): Promise<T> {
179
- const existing = actions.find(action => action.kind === kind && !consumed.has(action));
186
+ const existing = actions.find((action, index) => index >= dispatchedAt && action.kind === kind && !consumed.has(action));
180
187
  if (existing) {
181
188
  consumed.add(existing);
182
189
  return Promise.resolve(existing as T);
@@ -202,9 +209,18 @@ export async function connectGlspSocketDriver<TAction extends { readonly kind: s
202
209
  waiters.splice(at, 1);
203
210
  }
204
211
  // Naming what did arrive tells an operation the server declined
205
- // (a status or nothing at all) apart from a transport that hangs.
206
- const seen = actions.map(action => action.kind).join(', ') || 'nothing';
207
- reject(new Error(`No '${kind}' action within ${waitMs}ms on session ${clientSessionId}; received: ${seen}`));
212
+ // (a status or nothing at all) apart from a transport that hangs,
213
+ // split at the last dispatch, before which no match counts.
214
+ const kindsIn = (from: number, to?: number): string =>
215
+ actions
216
+ .slice(from, to)
217
+ .map(action => action.kind)
218
+ .join(', ') || 'nothing';
219
+ const seen =
220
+ dispatchedAt === 0
221
+ ? `received: ${kindsIn(0)}`
222
+ : `received before the last dispatch, which a wait does not match: ${kindsIn(0, dispatchedAt)}; since: ${kindsIn(dispatchedAt)}`;
223
+ reject(new Error(`No '${kind}' action within ${waitMs}ms on session ${clientSessionId}; ${seen}`));
208
224
  }, waitMs);
209
225
  waiters.push(waiter);
210
226
  });