@@ -368,15 +368,15 @@ describe('Create Rules Tests', () => {
368368 } ) ;
369369
370370 describe ( 'Create Project Rule' , ( ) => {
371- it ( 'Creates project rules for the full ancestor chain when assigning a nested sub- rule' , async ( ) => {
372- const root = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
371+ it ( 'Creates project rules for all ancestors when assigning deep child rule' , async ( ) => {
372+ const topLevelRule = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
373373 const child = await RulesService . createRule (
374374 batman ,
375375 'T.1.1' ,
376376 'Vehicle Requirements' ,
377377 rulesetId ,
378378 organization ,
379- root . ruleId
379+ topLevelRule . ruleId
380380 ) ;
381381 const grandchild = await RulesService . createRule ( batman , 'T.1.1.1' , 'Wheels' , rulesetId , organization , child . ruleId ) ;
382382
@@ -386,46 +386,46 @@ describe('Create Rules Tests', () => {
386386
387387 const projectRules = await RulesService . getProjectRules ( rulesetId , project . projectId , organization ) ;
388388 const assignedRuleIds = projectRules . map ( ( pr ) => pr . rule . ruleId ) ;
389- expect ( assignedRuleIds ) . toHaveLength ( 3 ) ;
390- expect ( assignedRuleIds ) . toEqual ( expect . arrayContaining ( [ root . ruleId , child . ruleId , grandchild . ruleId ] ) ) ;
389+ expect ( assignedRuleIds ) . toHaveLength ( 3 ) ; // grandchild, child, topLevelRule
390+ expect ( assignedRuleIds ) . toEqual ( expect . arrayContaining ( [ topLevelRule . ruleId , child . ruleId , grandchild . ruleId ] ) ) ;
391391 } ) ;
392392
393- it ( 'Creates project rules for shared ancestors when adding a sibling sub- rule' , async ( ) => {
394- const root = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
393+ it ( 'Creates project rules for shared ancestors when adding a sibling child rule' , async ( ) => {
394+ const topLevelRule = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
395395 const child = await RulesService . createRule (
396396 batman ,
397397 'T.1.1' ,
398398 'Vehicle Requirements' ,
399399 rulesetId ,
400400 organization ,
401- root . ruleId
401+ topLevelRule . ruleId
402402 ) ;
403403 const grandchild1 = await RulesService . createRule ( batman , 'T.1.1.1' , 'Wheels' , rulesetId , organization , child . ruleId ) ;
404404 const grandchild2 = await RulesService . createRule ( batman , 'T.1.1.2' , 'Brakes' , rulesetId , organization , child . ruleId ) ;
405405
406406 const project = await createTestProject ( aquaman , orgId , undefined , carId ) ;
407407
408408 await RulesService . createProjectRule ( aquaman , organization , grandchild1 . ruleId , project . projectId ) ;
409- // Adding a sibling must not error on the already-present parent/root and must not duplicate them.
409+ // adding sibling must not error or duplicate the already-present parent/root rules
410410 await RulesService . createProjectRule ( aquaman , organization , grandchild2 . ruleId , project . projectId ) ;
411411
412412 const projectRules = await RulesService . getProjectRules ( rulesetId , project . projectId , organization ) ;
413413 const assignedRuleIds = projectRules . map ( ( pr ) => pr . rule . ruleId ) ;
414- expect ( assignedRuleIds ) . toHaveLength ( 4 ) ;
414+ expect ( assignedRuleIds ) . toHaveLength ( 4 ) ; // grandchild1, grandchild2, child, topLevelRule
415415 expect ( assignedRuleIds ) . toEqual (
416- expect . arrayContaining ( [ root . ruleId , child . ruleId , grandchild1 . ruleId , grandchild2 . ruleId ] )
416+ expect . arrayContaining ( [ topLevelRule . ruleId , child . ruleId , grandchild1 . ruleId , grandchild2 . ruleId ] )
417417 ) ;
418418 } ) ;
419419
420- it ( 'does not assign descendants of the selected rule' , async ( ) => {
421- const root = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
420+ it ( 'Creating project rule does not assign descendants of the selected rule' , async ( ) => {
421+ const topLevelRule = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
422422 const child = await RulesService . createRule (
423423 batman ,
424424 'T.1.1' ,
425425 'Vehicle Requirements' ,
426426 rulesetId ,
427427 organization ,
428- root . ruleId
428+ topLevelRule . ruleId
429429 ) ;
430430 await RulesService . createRule ( batman , 'T.1.1.1' , 'Wheels' , rulesetId , organization , child . ruleId ) ;
431431
@@ -435,43 +435,43 @@ describe('Create Rules Tests', () => {
435435
436436 const projectRules = await RulesService . getProjectRules ( rulesetId , project . projectId , organization ) ;
437437 const assignedRuleIds = projectRules . map ( ( pr ) => pr . rule . ruleId ) ;
438- expect ( assignedRuleIds ) . toHaveLength ( 2 ) ;
439- expect ( assignedRuleIds ) . toEqual ( expect . arrayContaining ( [ root . ruleId , child . ruleId ] ) ) ;
438+ expect ( assignedRuleIds ) . toHaveLength ( 2 ) ; // child and topLevelRule, not grandchild
439+ expect ( assignedRuleIds ) . toEqual ( expect . arrayContaining ( [ topLevelRule . ruleId , child . ruleId ] ) ) ;
440440 } ) ;
441441
442- it ( 'does not assign deleted ancestors when assigning a nested sub-rule ' , async ( ) => {
443- const root = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
442+ it ( 'Creating project rule is refused entirely when an ancestor has been deleted ' , async ( ) => {
443+ const topLevelRule = await RulesService . createRule ( batman , 'T.1' , 'Technical Rules' , rulesetId , organization ) ;
444444 const child = await RulesService . createRule (
445445 batman ,
446446 'T.1.1' ,
447447 'Vehicle Requirements' ,
448448 rulesetId ,
449449 organization ,
450- root . ruleId
450+ topLevelRule . ruleId
451451 ) ;
452452 const grandchild = await RulesService . createRule ( batman , 'T.1.1.1' , 'Wheels' , rulesetId , organization , child . ruleId ) ;
453453
454- // Soft -delete the immediate parent directly so the grandchild remains assignable
454+ // soft -delete an ancestor so the chain to the top-level rule is broken
455455 await prisma . rule . update ( {
456456 where : { ruleId : child . ruleId } ,
457457 data : { dateDeleted : new Date ( ) , deletedBy : { connect : { userId : batman . userId } } }
458458 } ) ;
459459
460460 const project = await createTestProject ( aquaman , orgId , undefined , carId ) ;
461461
462- await RulesService . createProjectRule ( aquaman , organization , grandchild . ruleId , project . projectId ) ;
462+ // a broken chain means the grandchild could never display, so no rules are assigned to the project and an error is thrown
463+ await expect (
464+ async ( ) => await RulesService . createProjectRule ( aquaman , organization , grandchild . ruleId , project . projectId )
465+ ) . rejects . toThrow ( new DeletedException ( 'Rule' , child . ruleId ) ) ;
463466
464- // The walk stops at the deleted ancestor, so neither it nor the root above it are assigned.
467+ // nothing should have been assigned (not the grandchild, the deleted parent, or the root)
465468 const projectRules = await RulesService . getProjectRules ( rulesetId , project . projectId , organization ) ;
466- const assignedRuleIds = projectRules . map ( ( pr ) => pr . rule . ruleId ) ;
467- expect ( assignedRuleIds ) . toHaveLength ( 1 ) ;
468- expect ( assignedRuleIds ) . toEqual ( [ grandchild . ruleId ] ) ;
469+ expect ( projectRules ) . toHaveLength ( 0 ) ;
469470
470- // getProjectRules hides deleted rules, so assert directly that none was created for the deleted ancestor
471- const deletedAncestorProjectRule = await prisma . project_Rule . findUnique ( {
472- where : { ruleId_projectId : { ruleId : child . ruleId , projectId : project . projectId } }
471+ const grandchildProjectRule = await prisma . project_Rule . findUnique ( {
472+ where : { ruleId_projectId : { ruleId : grandchild . ruleId , projectId : project . projectId } }
473473 } ) ;
474- expect ( deletedAncestorProjectRule ) . toBeNull ( ) ;
474+ expect ( grandchildProjectRule ) . toBeNull ( ) ;
475475 } ) ;
476476
477477 it ( 'throws when the rule is already associated with the project' , async ( ) => {
0 commit comments