2828 */
2929
3030import { describe , it , expect , beforeEach } from 'vitest' ;
31+ import type { ExecutionContext } from '@objectstack/spec/kernel' ;
3132import { ObjectQL } from './engine.js' ;
3233import { ValidationError } from './validation/record-validator.js' ;
3334
@@ -127,8 +128,8 @@ function countingResolver(answer: unknown | (() => unknown)) {
127128 return { fn, asks } ;
128129}
129130
130- const ACTING = { userId : 'u1' , positions : [ 'sales_rep' ] } as any ;
131- const SYSTEM = { isSystem : true } as any ;
131+ const ACTING : ExecutionContext = { userId : 'u1' , positions : [ 'sales_rep' ] } ;
132+ const SYSTEM : ExecutionContext = { isSystem : true } ;
132133/** The `objects` slot of `/auth/me/permissions`: `edit` granted on crm_account, `delete` not. */
133134const MAP = { crm_account : { allowRead : true , allowEdit : true } } ;
134135const BOOM = Object . assign ( new Error ( 'permission store unreachable' ) , { code : 'AUTHZ_STORE_UNAVAILABLE' , status : 503 } ) ;
@@ -260,28 +261,28 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
260261
261262 it ( 'formula field on find — one resolution for the whole result set' , async ( ) => {
262263 seed ( 4 ) ;
263- const rows = await engine . find ( 'crm_case' , { context : ACTING } as any ) as Array < Record < string , unknown > > ;
264+ const rows = await engine . find ( 'crm_case' , { context : ACTING } ) as Array < Record < string , unknown > > ;
264265 expect ( rows ) . toHaveLength ( 4 ) ;
265266 expectFormulaCells ( rows , 1 ) ;
266267 expect ( asks ) . toHaveLength ( row . resolver ? 1 : 0 ) ;
267268 } ) ;
268269
269270 it ( 'formula field on findOne' , async ( ) => {
270271 seed ( 2 ) ;
271- const rec = await engine . findOne ( 'crm_case' , { where : { id : 'c1' } , context : ACTING } as any ) as Record < string , unknown > ;
272+ const rec = await engine . findOne ( 'crm_case' , { where : { id : 'c1' } , context : ACTING } ) as Record < string , unknown > ;
272273 expectFormulaCells ( [ rec ] , 1 ) ;
273274 expect ( asks ) . toHaveLength ( row . resolver ? 1 : 0 ) ;
274275 } ) ;
275276
276277 it ( 'formula field on the update echo' , async ( ) => {
277278 seed ( 1 ) ;
278- const echo = await engine . update ( 'crm_case' , { subject : 'renamed' } , { where : { id : 'c0' } , context : ACTING } as any ) as Record < string , unknown > ;
279+ const echo = await engine . update ( 'crm_case' , { subject : 'renamed' } , { where : { id : 'c0' } , context : ACTING } ) as Record < string , unknown > ;
279280 expectFormulaCells ( [ echo ] , 1 ) ;
280281 expect ( asks ) . toHaveLength ( row . resolver ? 1 : 0 ) ;
281282 } ) ;
282283
283284 it ( 'CEL defaultValue on insert — and the insert echo\'s formula reuses the same resolution' , async ( ) => {
284- const write = engine . insert ( 'crm_case' , { subject : 'n' } , { context : ACTING } as any ) ;
285+ const write = engine . insert ( 'crm_case' , { subject : 'n' } , { context : ACTING } ) ;
285286 if ( row . defaulted === 'refused' ) {
286287 // Fail CLOSED with the resolution's own error, untouched: ⛔ not read
287288 // as "no grants" (which would STORE `false`), and nothing written.
@@ -315,7 +316,7 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
315316 } ) ;
316317
317318 it ( 'a `required` field defaulted by `can`' , async ( ) => {
318- const write = engine . insert ( 'crm_gate' , { subject : 'g' } , { context : ACTING } as any ) ;
319+ const write = engine . insert ( 'crm_gate' , { subject : 'g' } , { context : ACTING } ) ;
319320 if ( row . defaulted === 'refused' ) {
320321 expect ( await refusal ( write ) ) . toBe ( BOOM ) ;
321322 expect ( created ( 'crm_gate' ) ) . toHaveLength ( 0 ) ;
@@ -344,14 +345,14 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
344345 fields : { flag : { type : 'boolean' , required : true , defaultValue : cel ( "current_user.can('crm_account', 'delete')" ) } } ,
345346 } as any , 'test-package' ) ;
346347 engine . registerEffectiveObjectPermissionsResolver ( countingResolver ( MAP ) . fn ) ;
347- await engine . insert ( 'crm_gate_denied' , { } , { context : ACTING } as any ) ;
348+ await engine . insert ( 'crm_gate_denied' , { } , { context : ACTING } ) ;
348349 expect ( created ( 'crm_gate_denied' ) [ 0 ] . data . flag ) . toBe ( false ) ;
349350 } ) ;
350351
351352 it ( 'ONE resolution for a write that needs the map three ways: default, option gate and response formula' , async ( ) => {
352353 const r = countingResolver ( MAP ) ;
353354 engine . registerEffectiveObjectPermissionsResolver ( r . fn ) ;
354- const echo = await engine . insert ( 'crm_case' , { subject : 'x' , stage : 'escalated' } , { context : ACTING } as any ) as Record < string , unknown > ;
355+ const echo = await engine . insert ( 'crm_case' , { subject : 'x' , stage : 'escalated' } , { context : ACTING } ) as Record < string , unknown > ;
355356 expect ( created ( 'crm_case' ) [ 0 ] . data ) . toMatchObject ( { stage : 'escalated' , edit_flag : true , delete_flag : false } ) ;
356357 expect ( echo . may_edit_account ) . toBe ( true ) ;
357358 expect ( r . asks ) . toHaveLength ( 1 ) ;
@@ -360,49 +361,49 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
360361 it ( 'ONE resolution for a batch insert of N rows, and for a by-id update picking a gated option' , async ( ) => {
361362 const r = countingResolver ( MAP ) ;
362363 engine . registerEffectiveObjectPermissionsResolver ( r . fn ) ;
363- await engine . insert ( 'crm_case' , Array . from ( { length : 6 } , ( _ , i ) => ( { subject : `b${ i } ` } ) ) as any , { context : ACTING } as any ) ;
364+ await engine . insert ( 'crm_case' , Array . from ( { length : 6 } , ( _ , i ) => ( { subject : `b${ i } ` } ) ) as any , { context : ACTING } ) ;
364365 expect ( created ( 'crm_case' ) ) . toHaveLength ( 6 ) ;
365366 expect ( created ( 'crm_case' ) . every ( ( w ) => w . data . edit_flag === true && w . data . delete_flag === false ) ) . toBe ( true ) ;
366367 expect ( r . asks ) . toHaveLength ( 1 ) ;
367368
368- await engine . update ( 'crm_case' , { stage : 'escalated' } , { where : { id : 'r_1' } , context : ACTING } as any ) ;
369+ await engine . update ( 'crm_case' , { stage : 'escalated' } , { where : { id : 'r_1' } , context : ACTING } ) ;
369370 expect ( r . asks ) . toHaveLength ( 2 ) ;
370371 } ) ;
371372
372373 it ( 'validate() previews the defaults and the option gate with ONE resolution' , async ( ) => {
373374 const r = countingResolver ( MAP ) ;
374375 engine . registerEffectiveObjectPermissionsResolver ( r . fn ) ;
375- const preview = await engine . validate ( 'crm_gate' , [ { subject : 'a' } , { subject : 'b' } ] , { mode : 'insert' , context : ACTING } as any ) ;
376+ const preview = await engine . validate ( 'crm_gate' , [ { subject : 'a' } , { subject : 'b' } ] , { mode : 'insert' , context : ACTING } ) ;
376377 expect ( preview . valid ) . toBe ( true ) ;
377378 expect ( r . asks ) . toHaveLength ( 1 ) ;
378379 } ) ;
379380
380381 it ( 'validate() rejects the same way the write does when a row\'s `can` default needed a failed resolution' , async ( ) => {
381382 engine . registerEffectiveObjectPermissionsResolver ( countingResolver ( ( ) => { throw BOOM ; } ) . fn ) ;
382383 await expect (
383- engine . validate ( 'crm_gate' , [ { subject : 'a' } ] , { mode : 'insert' , context : ACTING } as any ) ,
384+ engine . validate ( 'crm_gate' , [ { subject : 'a' } ] , { mode : 'insert' , context : ACTING } ) ,
384385 ) . rejects . toBe ( BOOM ) ;
385386 // A row that supplies the field previews without asking.
386- const supplied = await engine . validate ( 'crm_gate' , [ { subject : 'a' , flag : false } ] , { mode : 'insert' , context : ACTING } as any ) ;
387+ const supplied = await engine . validate ( 'crm_gate' , [ { subject : 'a' , flag : false } ] , { mode : 'insert' , context : ACTING } ) ;
387388 expect ( supplied . valid ) . toBe ( true ) ;
388389 } ) ;
389390
390391 it ( 'never cached across operations: two finds ask twice' , async ( ) => {
391392 seed ( 3 ) ;
392393 const r = countingResolver ( MAP ) ;
393394 engine . registerEffectiveObjectPermissionsResolver ( r . fn ) ;
394- await engine . find ( 'crm_case' , { context : ACTING } as any ) ;
395- await engine . find ( 'crm_case' , { context : ACTING } as any ) ;
395+ await engine . find ( 'crm_case' , { context : ACTING } ) ;
396+ await engine . find ( 'crm_case' , { context : ACTING } ) ;
396397 expect ( r . asks ) . toHaveLength ( 2 ) ;
397398 } ) ;
398399
399400 it ( 'control: no `can` anywhere ⇒ never asks, even a resolver that would THROW, and no warn' , async ( ) => {
400401 const r = countingResolver ( ( ) => { throw BOOM ; } ) ;
401402 engine . registerEffectiveObjectPermissionsResolver ( r . fn ) ;
402- const echo = await engine . insert ( 'crm_note' , { body : 'hi' } , { context : ACTING } as any ) as Record < string , unknown > ;
403+ const echo = await engine . insert ( 'crm_note' , { body : 'hi' } , { context : ACTING } ) as Record < string , unknown > ;
403404 expect ( echo . shout ) . toBe ( 'hi!' ) ;
404405 expect ( created ( 'crm_note' ) [ 0 ] . data . author ) . toBe ( 'u1' ) ;
405- const rows = await engine . find ( 'crm_note' , { context : ACTING } as any ) as Array < Record < string , unknown > > ;
406+ const rows = await engine . find ( 'crm_note' , { context : ACTING } ) as Array < Record < string , unknown > > ;
406407 expect ( rows [ 0 ] . shout ) . toBe ( 'hi!' ) ;
407408 expect ( r . asks ) . toHaveLength ( 0 ) ;
408409 expect ( formulaWarns ( ) ) . toHaveLength ( 0 ) ;
@@ -414,7 +415,7 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
414415 // The formula leg of the echo still reads null (with its warn): only the
415416 // default path was spared, because only the default path did not need it.
416417 await expect (
417- engine . insert ( 'crm_case' , { subject : 's' , edit_flag : true , delete_flag : false } , { context : ACTING } as any ) ,
418+ engine . insert ( 'crm_case' , { subject : 's' , edit_flag : true , delete_flag : false } , { context : ACTING } ) ,
418419 ) . resolves . toBeTruthy ( ) ;
419420 expect ( created ( 'crm_case' ) [ 0 ] . data ) . toMatchObject ( { edit_flag : true , delete_flag : false } ) ;
420421 expect ( r . asks ) . toHaveLength ( 1 ) ; // the echo's formulas — the default path asked nothing
@@ -424,8 +425,8 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
424425 seed ( 2 ) ;
425426 const r = countingResolver ( MAP ) ;
426427 engine . registerEffectiveObjectPermissionsResolver ( r . fn ) ;
427- await engine . find ( 'crm_case' , { context : SYSTEM } as any ) ;
428- await engine . find ( 'crm_case' , { } as any ) ;
428+ await engine . find ( 'crm_case' , { context : SYSTEM } ) ;
429+ await engine . find ( 'crm_case' , { } ) ;
429430 expect ( r . asks ) . toHaveLength ( 0 ) ;
430431 expect ( formulaWarns ( ) ) . toHaveLength ( 0 ) ;
431432 } ) ;
@@ -435,7 +436,7 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
435436 const out = await engine . insertMany ( 'crm_case' , [
436437 { subject : 'needs' } ,
437438 { subject : 'supplies' , edit_flag : false , delete_flag : true } ,
438- ] , { context : ACTING } as any ) ;
439+ ] , { context : ACTING } ) ;
439440 expect ( out [ 0 ] . ok ) . toBe ( false ) ;
440441 expect ( ( out [ 0 ] as { error : unknown } ) . error ) . toBe ( BOOM ) ;
441442 expect ( out [ 1 ] . ok ) . toBe ( true ) ;
@@ -444,13 +445,13 @@ describe('#20082 — formula fields and CEL defaults answer `can` from the secur
444445
445446 it ( 'a map that is not the published shape fails closed the same way (formula\'s door)' , async ( ) => {
446447 engine . registerEffectiveObjectPermissionsResolver ( countingResolver ( { crm_account : true } ) . fn ) ;
447- const err = await refusal ( engine . insert ( 'crm_case' , { subject : 'n' } , { context : ACTING } as any ) ) ;
448+ const err = await refusal ( engine . insert ( 'crm_case' , { subject : 'n' } , { context : ACTING } ) ) ;
448449 expect ( err ) . toBeInstanceOf ( TypeError ) ;
449450 expect ( String ( err . message ) ) . toContain ( "the entry for 'crm_account' is not an EffectiveObjectPermission" ) ;
450451 expect ( created ( 'crm_case' ) ) . toHaveLength ( 0 ) ;
451452
452453 seed ( 1 ) ;
453- const rows = await engine . find ( 'crm_case' , { context : ACTING } as any ) as Array < Record < string , unknown > > ;
454+ const rows = await engine . find ( 'crm_case' , { context : ACTING } ) as Array < Record < string , unknown > > ;
454455 expect ( rows [ 0 ] . may_edit_account ) . toBeNull ( ) ;
455456 expect ( formulaWarns ( ) . at ( - 1 ) ?. meta ) . toMatchObject ( { reason : 'permission-resolution-failed' } ) ;
456457 } ) ;
0 commit comments