@nanobpm/nano-workforce 0.178.5 → 0.179.0

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.
@@ -91,13 +91,15 @@ function harness() {
91
91
  };
92
92
  const click = (el: { dispatchEvent: (ev: unknown) => boolean }) =>
93
93
  el.dispatchEvent(new domWindow.Event("click", { bubbles: true, cancelable: true }));
94
+ const fire = (el: { dispatchEvent: (ev: unknown) => boolean }, type: string) =>
95
+ el.dispatchEvent(new domWindow.Event(type, { bubbles: true, cancelable: true }));
94
96
 
95
- return { host, calls, teardown, flush, click };
97
+ return { host, calls, teardown, flush, click, fire };
96
98
  }
97
99
 
98
100
  const posts = (calls: FetchCall[], url: string) => calls.filter((c) => c.method === "POST" && c.url === url);
99
101
 
100
- test("#569: Dispatch dispatches via the in-DOM confirmation even when native window.confirm is suppressed", async () => {
102
+ test("#569/#729: Dispatch dispatches via the in-DOM confirmation with the repo envelope even when native window.confirm is suppressed", async () => {
101
103
  const h = harness();
102
104
  try {
103
105
  await h.flush();
@@ -105,7 +107,8 @@ test("#569: Dispatch dispatches via the in-DOM confirmation even when native win
105
107
  assert(dispatchBtn, "the mount must render a Dispatch button for the staged proposal");
106
108
 
107
109
  // Click Dispatch — with a suppressed native confirm, the PRE-FIX mount POSTs nothing; the fixed
108
- // mount instead reveals an in-DOM "Confirm dispatch" step and has NOT yet POSTed.
110
+ // mount instead reveals an in-DOM "Confirm dispatch" step (with the #729 envelope fields) and has
111
+ // NOT yet POSTed.
109
112
  h.click(dispatchBtn);
110
113
  await h.flush();
111
114
  assertEquals(posts(h.calls, DISPATCH_URL).length, 0, "Dispatch must not POST before the operator confirms in-DOM");
@@ -113,12 +116,67 @@ test("#569: Dispatch dispatches via the in-DOM confirmation even when native win
113
116
  assert(confirmBtn, "clicking Dispatch must reveal an in-DOM Confirm-dispatch control (#569), not call window.confirm");
114
117
  assert(!h.host.querySelector("[data-dispatch]"), "the plain Dispatch button is replaced by the inline confirmation while it is open");
115
118
 
116
- // Confirm the digest is POSTed to the dispatch door, with no reliance on a native modal.
119
+ // The operator supplies the repository-isolation envelope the door now requires (#729): a staged
120
+ // proposal carries no repo metadata, so the cockpit collects it here.
121
+ const repoInput = h.host.querySelector("[data-dispatch-repository]");
122
+ const baseInput = h.host.querySelector("[data-dispatch-base]");
123
+ assert(repoInput && baseInput, "the Dispatch confirmation must expose repository + base-branch fields (#729)");
124
+ repoInput.value = "acme/widgets";
125
+ baseInput.value = "main";
126
+
127
+ // Confirm — the digest AND the envelope are POSTed to the dispatch door, with no reliance on a native modal.
117
128
  h.click(confirmBtn);
118
129
  await h.flush();
119
130
  const dispatched = posts(h.calls, DISPATCH_URL);
120
131
  assertEquals(dispatched.length, 1, "confirming in-DOM must POST exactly once to the dispatch door");
121
- assertEquals(JSON.parse(dispatched[0].body), { digest: PROPOSAL.digest }, "the dispatch POST carries the staged digest");
132
+ assertEquals(
133
+ JSON.parse(dispatched[0].body),
134
+ { digest: PROPOSAL.digest, repository: "acme/widgets", baseBranch: "main" },
135
+ "the dispatch POST carries the staged digest and the operator-supplied repo envelope",
136
+ );
137
+ } finally {
138
+ h.teardown();
139
+ }
140
+ });
141
+
142
+ test("#729: Dispatch checkout-less posts `repoless: true` (no repo envelope) instead of repository/baseBranch", async () => {
143
+ const h = harness();
144
+ try {
145
+ await h.flush();
146
+ h.click(h.host.querySelector("[data-dispatch]"));
147
+ await h.flush();
148
+ const box = h.host.querySelector("[data-dispatch-repoless]");
149
+ assert(box, "the Dispatch confirmation must expose a checkout-less (repoless) opt-out (#729)");
150
+ box.checked = true;
151
+ h.fire(box, "change");
152
+ await h.flush();
153
+
154
+ h.click(h.host.querySelector("[data-dispatch-confirm]"));
155
+ await h.flush();
156
+ const dispatched = posts(h.calls, DISPATCH_URL);
157
+ assertEquals(dispatched.length, 1, "confirming a checkout-less dispatch must POST exactly once");
158
+ assertEquals(
159
+ JSON.parse(dispatched[0].body),
160
+ { digest: PROPOSAL.digest, repoless: true },
161
+ "a checkout-less dispatch posts `repoless: true` and omits repository/baseBranch (mutually exclusive, #729)",
162
+ );
163
+ } finally {
164
+ h.teardown();
165
+ }
166
+ });
167
+
168
+ test("#729: confirming a dispatch with neither the repo envelope nor checkout-less does NOT POST (keeps the confirmation open)", async () => {
169
+ const h = harness();
170
+ try {
171
+ await h.flush();
172
+ h.click(h.host.querySelector("[data-dispatch]"));
173
+ await h.flush();
174
+ // Confirm with blank repository/baseBranch and checkout-less unticked — the door would 400, so the
175
+ // mount guards client-side: no POST, and the confirmation stays open so the operator can fix it.
176
+ h.click(h.host.querySelector("[data-dispatch-confirm]"));
177
+ await h.flush();
178
+ assertEquals(posts(h.calls, DISPATCH_URL).length, 0, "an incomplete envelope must not POST to the dispatch door (#729)");
179
+ assert(h.host.querySelector("[data-dispatch-confirm]"), "the confirmation stays open so the operator can supply the envelope");
122
180
  } finally {
123
181
  h.teardown();
124
182
  }