|
25 | 25 | * on a read that names the record, read-only; |
26 | 26 | * - control: an administrator, and the approval engine's own reads as the |
27 | 27 | * system, are unchanged; |
28 | | - * - for every caller, the data door's ids equal the approvals door's. |
| 28 | + * - for every caller, the data door's ids equal the approvals door's, by |
| 29 | + * list and by id (the by-id read is what a request's record page makes). |
29 | 30 | * |
30 | 31 | * ## The rig |
31 | 32 | * |
@@ -201,6 +202,26 @@ async function byId(rig: Rig, context: any, id: string): Promise<{ record?: any; |
201 | 202 | } |
202 | 203 | } |
203 | 204 |
|
| 205 | +/** |
| 206 | + * By id, the data door against the approvals door, for every caller and both |
| 207 | + * requests: the record read a `sys_approval_request` record page makes (its |
| 208 | + * highlights and details) is served exactly when `getRequest` serves the |
| 209 | + * request — and a refused one answers as a missing one. |
| 210 | + */ |
| 211 | +async function expectByIdParity(rig: Rig, callers: any[]): Promise<void> { |
| 212 | + for (const ctx of callers) { |
| 213 | + for (const id of [rig.ids.requestA, rig.ids.requestB]) { |
| 214 | + const served = (await rig.svc.getRequest(id, ctx)) !== null; |
| 215 | + const answer = await byId(rig, ctx, id); |
| 216 | + expect(answer.record?.id ?? null, `${ctx.userId} ${id}`).toBe(served ? id : null); |
| 217 | + if (!served) { |
| 218 | + expect({ code: answer.error?.code, status: answer.error?.status }, `${ctx.userId} ${id}`) |
| 219 | + .toEqual({ code: 'RECORD_NOT_FOUND', status: 404 }); |
| 220 | + } |
| 221 | + } |
| 222 | + } |
| 223 | +} |
| 224 | + |
204 | 225 | describe('the record-reader tier OFF (the default)', () => { |
205 | 226 | it('a non-participant who cannot read the record sees no request: list, a record\'s list, count, grouped count', async () => { |
206 | 227 | const rig = await boot(); |
@@ -270,6 +291,11 @@ describe('the record-reader tier OFF (the default)', () => { |
270 | 291 | } |
271 | 292 | } |
272 | 293 | }); |
| 294 | + |
| 295 | + it('one rule, two doors, by id: a request\'s record page reads it exactly when the approvals door serves it', async () => { |
| 296 | + const rig = await boot(); |
| 297 | + await expectByIdParity(rig, [asUser(OUTSIDER), asUser(READER), asUser(SUBMITTER_A), asUser(SUBMITTER_B), asUser(APPROVER), ADMIN]); |
| 298 | + }); |
273 | 299 | }); |
274 | 300 |
|
275 | 301 | describe('the record-reader tier ON for the object', () => { |
@@ -317,6 +343,11 @@ describe('the record-reader tier ON for the object', () => { |
317 | 343 | } |
318 | 344 | } |
319 | 345 | }); |
| 346 | + |
| 347 | + it('one rule, two doors, by id, with the tier on as well', async () => { |
| 348 | + const rig = await boot(ON); |
| 349 | + await expectByIdParity(rig, [asUser(OUTSIDER), asUser(READER), asUser(SUBMITTER_A), asUser(SUBMITTER_B), asUser(APPROVER), ADMIN]); |
| 350 | + }); |
320 | 351 | }); |
321 | 352 |
|
322 | 353 | describe('fails closed', () => { |
|
0 commit comments