abilityBuilder.test.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. import { describe, test, expect, vi, beforeEach } from 'vitest'
  2. //@ts-expect-error false error
  3. import type { MongoAbility } from '@casl/ability/dist/types/Ability'
  4. import type { AbilitiesType, AccessProfile } from '~/types/interfaces'
  5. import AbilityBuilder from '~/services/rights/abilityBuilder'
  6. import { ABILITIES } from '~/types/enum/enums'
  7. import type OrganizationProfile from '~/models/Organization/OrganizationProfile'
  8. // Mock the abilities config to return only test data
  9. vi.mock('~/config/abilities/config-precompiled', () => {
  10. return {
  11. default: {
  12. 'subject1': {
  13. action: 'display',
  14. conditions: [{ function: 'accessHasAnyProfile', parameters: ['guardian'] }]
  15. },
  16. 'subject2': {
  17. action: 'display',
  18. conditions: [{ function: 'organizationIsSchool' }]
  19. }
  20. }
  21. }
  22. })
  23. let ability: MongoAbility
  24. let accessProfile: AccessProfile
  25. let organizationProfile: OrganizationProfile
  26. let abilityBuilder: AbilityBuilder
  27. // Mock the content of the config yaml files
  28. // > This must be done in the global scope: https://vitest.dev/api/vi.html#vi-mock
  29. const doc = {
  30. abilities: {
  31. subject1: {
  32. action: ABILITIES.READ,
  33. conditions: [
  34. {
  35. function: 'fct1',
  36. parameters: ['param1'],
  37. expectedResult: true,
  38. },
  39. ],
  40. },
  41. subject2: {
  42. action: ABILITIES.READ,
  43. conditions: {
  44. function: 'fct2',
  45. parameters: ['param2'],
  46. expectedResult: false,
  47. },
  48. },
  49. },
  50. }
  51. vi.mock('yaml-import', () => {
  52. return {
  53. read: vi.fn((data: string) => doc),
  54. }
  55. })
  56. beforeEach(() => {
  57. ability = vi.fn() as any as MongoAbility
  58. accessProfile = vi.fn() as any as AccessProfile
  59. organizationProfile = vi.fn() as any as OrganizationProfile
  60. abilityBuilder = new AbilityBuilder(
  61. ability,
  62. accessProfile,
  63. organizationProfile,
  64. )
  65. })
  66. describe('buildAbilities', () => {
  67. test('base call', () => {
  68. const roleAbilities: Array<AbilitiesType> = [
  69. { action: ABILITIES.READ, subject: 'subject1' },
  70. { action: ABILITIES.READ, subject: 'subject2' },
  71. ]
  72. const configAbilities: Array<AbilitiesType> = [
  73. { action: ABILITIES.READ, subject: 'subject3' },
  74. { action: ABILITIES.READ, subject: 'subject4' },
  75. ]
  76. const allAbilities: Array<AbilitiesType> =
  77. roleAbilities.concat(configAbilities)
  78. abilityBuilder.buildAbilitiesFromRoles = vi.fn(() => roleAbilities)
  79. abilityBuilder.buildAbilitiesFromConfig = vi.fn(() => configAbilities)
  80. ability.update = vi.fn()
  81. const result = abilityBuilder.buildAbilities()
  82. expect(ability.update).toHaveBeenCalledTimes(2)
  83. expect(ability.update).toHaveBeenCalledWith(roleAbilities)
  84. expect(ability.update).toHaveBeenCalledWith(allAbilities)
  85. expect(abilityBuilder.buildAbilitiesFromRoles).toHaveBeenCalledOnce()
  86. expect(abilityBuilder.buildAbilitiesFromConfig).toHaveBeenCalledOnce()
  87. expect(result).toEqual(allAbilities)
  88. })
  89. })
  90. describe('buildAbilitiesFromRoles', () => {
  91. test('calls roleUtils', () => {
  92. accessProfile.roles = [
  93. 'ROLE_EVENTS_VIEW',
  94. 'ROLE_COURSES',
  95. 'ROLE_TEACHER_CORE',
  96. 'ROLE_OTHER',
  97. ]
  98. const expected = [
  99. { subject: 'events', action: 'read' },
  100. { subject: 'courses', action: 'manage' },
  101. { subject: 'other', action: 'manage' },
  102. ]
  103. expect(abilityBuilder.buildAbilitiesFromRoles()).toEqual(expected)
  104. })
  105. })
  106. describe('buildAbilitiesFromConfig', () => {
  107. test('calls roleUtils', () => {
  108. abilityBuilder.hasConfigAbility = vi.fn(() => true)
  109. expect(abilityBuilder.buildAbilitiesFromConfig()).toEqual([
  110. { action: 'display', subject: 'subject1', inverted: false },
  111. { action: 'display', subject: 'subject2', inverted: false },
  112. ])
  113. })
  114. })
  115. describe('hasConfigAbility', () => {
  116. beforeEach(() => {
  117. accessProfile.isGuardian = true
  118. organizationProfile.isSchool = true
  119. organizationProfile.isCmf = false
  120. })
  121. test('fulfill all conditions', () => {
  122. const conditions = [
  123. { function: 'accessHasAnyProfile', parameters: ['guardian', 'payer'] },
  124. { function: 'organizationIsSchool' },
  125. ]
  126. expect(abilityBuilder.hasConfigAbility(conditions)).toBeTruthy()
  127. })
  128. test('fulfill at least one condition', () => {
  129. const conditions = [
  130. { function: 'accessHasAnyProfile', parameters: ['guardian', 'payer'] },
  131. { function: 'organizationIsCmf' },
  132. ]
  133. expect(abilityBuilder.hasConfigAbility(conditions)).toBeFalsy()
  134. })
  135. test('fulfill none of the conditions', () => {
  136. const conditions = [{ function: 'organizationIsCmf' }]
  137. expect(abilityBuilder.hasConfigAbility(conditions)).toBeFalsy()
  138. })
  139. })
  140. describe('execAndValidateCondition', () => {
  141. test('accessHasAllRoleAbilities', () => {
  142. ability.can = vi.fn((action: string, subject: string) => {
  143. return (
  144. action === 'read' && (subject === 'subject1' || subject === 'subject2')
  145. )
  146. })
  147. expect(
  148. // @ts-expect-error accessing protected method for testing purposes
  149. abilityBuilder.execAndValidateCondition({
  150. function: 'accessHasAllRoleAbilities',
  151. parameters: [
  152. { action: ABILITIES.READ, subject: 'subject1' },
  153. { action: ABILITIES.READ, subject: 'subject2' },
  154. ],
  155. }),
  156. ).toBeTruthy()
  157. expect(
  158. // @ts-expect-error accessing protected method for testing purposes
  159. abilityBuilder.execAndValidateCondition({
  160. function: 'accessHasAllRoleAbilities',
  161. parameters: [
  162. { action: ABILITIES.READ, subject: 'subject1' },
  163. { action: ABILITIES.READ, subject: 'subject3' },
  164. ],
  165. }),
  166. ).toBeFalsy()
  167. })
  168. test('accessHasAnyRoleAbility', () => {
  169. ability.can = vi.fn((action: string, subject: string) => {
  170. return action === 'read' && subject === 'subject1'
  171. })
  172. expect(
  173. // @ts-expect-error accessing protected method for testing purposes
  174. abilityBuilder.execAndValidateCondition({
  175. function: 'accessHasAnyRoleAbility',
  176. parameters: [
  177. { action: ABILITIES.READ, subject: 'subject1' },
  178. { action: ABILITIES.READ, subject: 'subject2' },
  179. ],
  180. }),
  181. ).toBeTruthy()
  182. expect(
  183. // @ts-expect-error accessing protected method for testing purposes
  184. abilityBuilder.execAndValidateCondition({
  185. function: 'accessHasAnyRoleAbility',
  186. parameters: [{ action: ABILITIES.READ, subject: 'subject2' }],
  187. }),
  188. ).toBeFalsy()
  189. })
  190. test('accessHasAnyProfile', () => {
  191. accessProfile.isMember = true
  192. accessProfile.isGuardian = true
  193. accessProfile.isPayer = true
  194. expect(
  195. // @ts-expect-error accessing protected method for testing purposes
  196. abilityBuilder.execAndValidateCondition({
  197. function: 'accessHasAnyProfile',
  198. parameters: ['guardian', 'payer'],
  199. }),
  200. ).toBeTruthy()
  201. expect(
  202. // @ts-expect-error accessing protected method for testing purposes
  203. abilityBuilder.execAndValidateCondition({
  204. function: 'accessHasAnyProfile',
  205. parameters: ['guardian', 'caMember'],
  206. }),
  207. ).toBeTruthy()
  208. expect(
  209. // @ts-expect-error accessing protected method for testing purposes
  210. abilityBuilder.execAndValidateCondition({
  211. function: 'accessHasAnyProfile',
  212. parameters: ['caMember'],
  213. }),
  214. ).toBeFalsy()
  215. })
  216. test('organizationHasAllModules', () => {
  217. // @ts-expect-error for testing purposes
  218. organizationProfile.hasModule = vi.fn(
  219. (module: string) => module === 'module1' || module === 'module2',
  220. )
  221. expect(
  222. // @ts-expect-error accessing protected method for testing purposes
  223. abilityBuilder.execAndValidateCondition({
  224. function: 'organizationHasAllModules',
  225. parameters: ['module1', 'module2'],
  226. }),
  227. ).toBeTruthy()
  228. expect(
  229. // @ts-expect-error accessing protected method for testing purposes
  230. abilityBuilder.execAndValidateCondition({
  231. function: 'organizationHasAllModules',
  232. parameters: ['module1', 'module3'],
  233. }),
  234. ).toBeFalsy()
  235. expect(
  236. // @ts-expect-error accessing protected method for testing purposes
  237. abilityBuilder.execAndValidateCondition({
  238. function: 'organizationHasAllModules',
  239. parameters: ['module3'],
  240. }),
  241. ).toBeFalsy()
  242. })
  243. test('organizationHasAnyModule', () => {
  244. // @ts-expect-error accessing non-existent property for testing purposes
  245. organizationProfile.hasModule = vi.fn(
  246. (module: string) => module === 'module1' || module === 'module2',
  247. )
  248. expect(
  249. // @ts-expect-error accessing protected method for testing purposes
  250. abilityBuilder.execAndValidateCondition({
  251. function: 'organizationHasAnyModule',
  252. parameters: ['module1', 'module2'],
  253. }),
  254. ).toBeTruthy()
  255. expect(
  256. // @ts-expect-error accessing protected method for testing purposes
  257. abilityBuilder.execAndValidateCondition({
  258. function: 'organizationHasAnyModule',
  259. parameters: ['module1', 'module3'],
  260. }),
  261. ).toBeTruthy()
  262. expect(
  263. // @ts-expect-error accessing protected method for testing purposes
  264. abilityBuilder.execAndValidateCondition({
  265. function: 'organizationHasAnyModule',
  266. parameters: ['module3'],
  267. }),
  268. ).toBeFalsy()
  269. })
  270. test('organizationHasAnyModule', () => {
  271. accessProfile.isAdminAccount = true
  272. expect(
  273. // @ts-expect-error accessing protected method for testing purposes
  274. abilityBuilder.execAndValidateCondition({
  275. function: 'accessIsAdminAccount',
  276. }),
  277. ).toBeTruthy()
  278. accessProfile.isAdminAccount = false
  279. expect(
  280. // @ts-expect-error accessing protected method for testing purposes
  281. abilityBuilder.execAndValidateCondition({
  282. function: 'accessIsAdminAccount',
  283. }),
  284. ).toBeFalsy()
  285. })
  286. test('organizationIsSchool', () => {
  287. organizationProfile.isSchool = true
  288. expect(
  289. // @ts-expect-error accessing protected method for testing purposes
  290. abilityBuilder.execAndValidateCondition({
  291. function: 'organizationIsSchool',
  292. }),
  293. ).toBeTruthy()
  294. organizationProfile.isSchool = false
  295. expect(
  296. // @ts-expect-error accessing protected method for testing purposes
  297. abilityBuilder.execAndValidateCondition({
  298. function: 'organizationIsSchool',
  299. }),
  300. ).toBeFalsy()
  301. })
  302. test('organizationIsArtist', () => {
  303. organizationProfile.isArtist = true
  304. expect(
  305. // @ts-expect-error accessing protected method for testing purposes
  306. abilityBuilder.execAndValidateCondition({
  307. function: 'organizationIsArtist',
  308. }),
  309. ).toBeTruthy()
  310. organizationProfile.isArtist = false
  311. expect(
  312. // @ts-expect-error accessing protected method for testing purposes
  313. abilityBuilder.execAndValidateCondition({
  314. function: 'organizationIsArtist',
  315. }),
  316. ).toBeFalsy()
  317. })
  318. test('organizationIsManagerProduct', () => {
  319. organizationProfile.isManagerProduct = true
  320. expect(
  321. // @ts-expect-error accessing protected method for testing purposes
  322. abilityBuilder.execAndValidateCondition({
  323. function: 'organizationIsManagerProduct',
  324. }),
  325. ).toBeTruthy()
  326. organizationProfile.isManagerProduct = false
  327. expect(
  328. // @ts-expect-error accessing protected method for testing purposes
  329. abilityBuilder.execAndValidateCondition({
  330. function: 'organizationIsManagerProduct',
  331. }),
  332. ).toBeFalsy()
  333. })
  334. test('organizationHasChildren', () => {
  335. organizationProfile.hasChildren = true
  336. expect(
  337. // @ts-expect-error accessing protected method for testing purposes
  338. abilityBuilder.execAndValidateCondition({
  339. function: 'organizationHasChildren',
  340. }),
  341. ).toBeTruthy()
  342. organizationProfile.hasChildren = false
  343. expect(
  344. // @ts-expect-error accessing protected method for testing purposes
  345. abilityBuilder.execAndValidateCondition({
  346. function: 'organizationHasChildren',
  347. }),
  348. ).toBeFalsy()
  349. })
  350. test('organizationIsAssociation', () => {
  351. organizationProfile.isAssociation = true
  352. expect(
  353. // @ts-expect-error accessing protected method for testing purposes
  354. abilityBuilder.execAndValidateCondition({
  355. function: 'organizationIsAssociation',
  356. }),
  357. ).toBeTruthy()
  358. organizationProfile.isAssociation = false
  359. expect(
  360. // @ts-expect-error accessing protected method for testing purposes
  361. abilityBuilder.execAndValidateCondition({
  362. function: 'organizationIsAssociation',
  363. }),
  364. ).toBeFalsy()
  365. })
  366. test('organizationIsShowAdherentList', () => {
  367. organizationProfile.isShowAdherentList = true
  368. expect(
  369. // @ts-expect-error accessing protected method for testing purposes
  370. abilityBuilder.execAndValidateCondition({
  371. function: 'organizationIsShowAdherentList',
  372. }),
  373. ).toBeTruthy()
  374. organizationProfile.isShowAdherentList = false
  375. expect(
  376. // @ts-expect-error accessing protected method for testing purposes
  377. abilityBuilder.execAndValidateCondition({
  378. function: 'organizationIsShowAdherentList',
  379. }),
  380. ).toBeFalsy()
  381. })
  382. test('organizationIsCmf', () => {
  383. organizationProfile.isCmf = true
  384. expect(
  385. // @ts-expect-error accessing protected method for testing purposes
  386. abilityBuilder.execAndValidateCondition({
  387. function: 'organizationIsCmf',
  388. }),
  389. ).toBeTruthy()
  390. organizationProfile.isCmf = false
  391. expect(
  392. // @ts-expect-error accessing protected method for testing purposes
  393. abilityBuilder.execAndValidateCondition({
  394. function: 'organizationIsCmf',
  395. }),
  396. ).toBeFalsy()
  397. })
  398. test('organizationHasWebsite', () => {
  399. organizationProfile.getWebsite = 'https://example.com'
  400. expect(
  401. // @ts-expect-error accessing protected method for testing purposes
  402. abilityBuilder.execAndValidateCondition({
  403. function: 'organizationHasWebsite',
  404. }),
  405. ).toBeTruthy()
  406. organizationProfile.getWebsite = null
  407. expect(
  408. // @ts-expect-error accessing protected method for testing purposes
  409. abilityBuilder.execAndValidateCondition({
  410. function: 'organizationHasWebsite',
  411. }),
  412. ).toBeFalsy()
  413. })
  414. test('with expected result', () => {
  415. organizationProfile.getWebsite = 'https://example.com'
  416. expect(
  417. // @ts-expect-error accessing protected method for testing purposes
  418. abilityBuilder.execAndValidateCondition({
  419. function: 'organizationHasWebsite',
  420. expectedResult: true,
  421. }),
  422. ).toBeTruthy()
  423. expect(
  424. // @ts-expect-error accessing protected method for testing purposes
  425. abilityBuilder.execAndValidateCondition({
  426. function: 'organizationHasWebsite',
  427. // @ts-expect-error testing with intentionally wrong type
  428. expectedResult: 'abc',
  429. }),
  430. ).toBeFalsy()
  431. })
  432. test('invalid function', () => {
  433. expect(
  434. // @ts-expect-error accessing protected method for testing purposes
  435. () => abilityBuilder.execAndValidateCondition({ function: 'invalid' }),
  436. ).toThrowError('unknown condition function : invalid')
  437. })
  438. })
  439. describe('hasRoleAbility', () => {
  440. beforeEach(() => {
  441. ability.can = vi.fn((action: string, subject: string) => {
  442. return action === 'read' && subject === 'a_subject'
  443. })
  444. })
  445. test('owned ability', () => {
  446. expect(
  447. abilityBuilder.hasRoleAbility({
  448. action: ABILITIES.READ,
  449. subject: 'a_subject',
  450. }),
  451. ).toBeTruthy()
  452. })
  453. test('not owned ability', () => {
  454. expect(
  455. abilityBuilder.hasRoleAbility({
  456. action: ABILITIES.READ,
  457. subject: 'other_subject',
  458. }),
  459. ).toBeFalsy()
  460. })
  461. })
  462. describe('hasAllRoleAbilities', () => {
  463. beforeEach(() => {
  464. ability.can = vi.fn((action: string, subject: string) => {
  465. return (
  466. action === 'read' && (subject === 'subject1' || subject === 'subject2')
  467. )
  468. })
  469. })
  470. test('own all abilities', () => {
  471. const result = abilityBuilder.hasAllRoleAbilities([
  472. { action: ABILITIES.READ, subject: 'subject1' },
  473. { action: ABILITIES.READ, subject: 'subject2' },
  474. ])
  475. expect(result).toBeTruthy()
  476. })
  477. test('own at least one ability', () => {
  478. const result = abilityBuilder.hasAllRoleAbilities([
  479. { action: ABILITIES.READ, subject: 'subject1' },
  480. { action: ABILITIES.READ, subject: 'subject3' },
  481. ])
  482. expect(result).toBeFalsy()
  483. })
  484. test('own none of the abilities', () => {
  485. const result = abilityBuilder.hasAllRoleAbilities([
  486. { action: ABILITIES.READ, subject: 'subject3' },
  487. { action: ABILITIES.READ, subject: 'subject4' },
  488. ])
  489. expect(result).toBeFalsy()
  490. })
  491. })
  492. describe('hasAnyRoleAbility', () => {
  493. beforeEach(() => {
  494. ability.can = vi.fn((action: string, subject: string) => {
  495. return (
  496. action === 'read' && (subject === 'subject1' || subject === 'subject2')
  497. )
  498. })
  499. })
  500. test('has all abilities', () => {
  501. const result = abilityBuilder.hasAnyRoleAbility([
  502. { action: ABILITIES.READ, subject: 'subject1' },
  503. { action: ABILITIES.READ, subject: 'subject2' },
  504. ])
  505. expect(result).toBeTruthy()
  506. })
  507. test('has at least one ability', () => {
  508. const result = abilityBuilder.hasAnyRoleAbility([
  509. { action: ABILITIES.READ, subject: 'subject1' },
  510. { action: ABILITIES.READ, subject: 'subject3' },
  511. ])
  512. expect(result).toBeTruthy()
  513. })
  514. test('any none of the abilites', () => {
  515. const result = abilityBuilder.hasAnyRoleAbility([
  516. { action: ABILITIES.READ, subject: 'subject3' },
  517. { action: ABILITIES.READ, subject: 'subject4' },
  518. ])
  519. expect(result).toBeFalsy()
  520. })
  521. })
  522. describe('hasProfile', () => {
  523. test('owned profiles', () => {
  524. accessProfile.isAdmin = true
  525. accessProfile.isAdministratifManager = true
  526. accessProfile.isPedagogicManager = true
  527. accessProfile.isFinancialManager = true
  528. accessProfile.isCaMember = true
  529. accessProfile.isStudent = true
  530. accessProfile.isTeacher = true
  531. accessProfile.isMember = true
  532. accessProfile.isOther = true
  533. accessProfile.isGuardian = true
  534. accessProfile.isPayer = true
  535. expect(abilityBuilder.hasProfile('admin')).toBeTruthy()
  536. expect(abilityBuilder.hasProfile('administratifManager')).toBeTruthy()
  537. expect(abilityBuilder.hasProfile('pedagogicManager')).toBeTruthy()
  538. expect(abilityBuilder.hasProfile('financialManager')).toBeTruthy()
  539. expect(abilityBuilder.hasProfile('caMember')).toBeTruthy()
  540. expect(abilityBuilder.hasProfile('student')).toBeTruthy()
  541. expect(abilityBuilder.hasProfile('teacher')).toBeTruthy()
  542. expect(abilityBuilder.hasProfile('member')).toBeTruthy()
  543. expect(abilityBuilder.hasProfile('other')).toBeTruthy()
  544. expect(abilityBuilder.hasProfile('guardian')).toBeTruthy()
  545. expect(abilityBuilder.hasProfile('payor')).toBeTruthy()
  546. })
  547. test('not owned profiles', () => {
  548. accessProfile.isAdmin = false
  549. accessProfile.isAdministratifManager = false
  550. accessProfile.isPedagogicManager = false
  551. accessProfile.isFinancialManager = false
  552. accessProfile.isCaMember = false
  553. accessProfile.isStudent = false
  554. accessProfile.isTeacher = false
  555. accessProfile.isMember = false
  556. accessProfile.isOther = false
  557. accessProfile.isGuardian = false
  558. accessProfile.isPayer = false
  559. expect(abilityBuilder.hasProfile('admin')).toBeFalsy()
  560. expect(abilityBuilder.hasProfile('administratifManager')).toBeFalsy()
  561. expect(abilityBuilder.hasProfile('pedagogicManager')).toBeFalsy()
  562. expect(abilityBuilder.hasProfile('financialManager')).toBeFalsy()
  563. expect(abilityBuilder.hasProfile('caMember')).toBeFalsy()
  564. expect(abilityBuilder.hasProfile('student')).toBeFalsy()
  565. expect(abilityBuilder.hasProfile('teacher')).toBeFalsy()
  566. expect(abilityBuilder.hasProfile('member')).toBeFalsy()
  567. expect(abilityBuilder.hasProfile('other')).toBeFalsy()
  568. expect(abilityBuilder.hasProfile('guardian')).toBeFalsy()
  569. expect(abilityBuilder.hasProfile('payor')).toBeFalsy()
  570. })
  571. })
  572. describe('hasAnyProfile', () => {
  573. beforeEach(() => {
  574. accessProfile.isMember = true
  575. accessProfile.isGuardian = true
  576. accessProfile.isPayer = true
  577. })
  578. test('own all profiles', () => {
  579. expect(
  580. abilityBuilder.hasAnyProfile(['member', 'guardian', 'payor']),
  581. ).toBeTruthy()
  582. })
  583. test('own at least one profile', () => {
  584. expect(abilityBuilder.hasAnyProfile(['member', 'caMember'])).toBeTruthy()
  585. })
  586. test('own none of the profiles', () => {
  587. expect(
  588. abilityBuilder.hasAnyProfile(['caMember', 'isFinancialManager']),
  589. ).toBeFalsy()
  590. })
  591. })
  592. describe('hasAllProfiles', () => {
  593. beforeEach(() => {
  594. accessProfile.isMember = true
  595. accessProfile.isGuardian = true
  596. accessProfile.isPayer = true
  597. })
  598. test('own all profiles', () => {
  599. expect(
  600. abilityBuilder.hasAllProfiles(['member', 'guardian', 'payor']),
  601. ).toBeTruthy()
  602. })
  603. test('own only one of the profiles', () => {
  604. expect(abilityBuilder.hasAllProfiles(['member', 'caMember'])).toBeFalsy()
  605. })
  606. test('own none of the profiles', () => {
  607. expect(
  608. abilityBuilder.hasAllProfiles(['caMember', 'isFinancialManager']),
  609. ).toBeFalsy()
  610. })
  611. })
  612. describe('hasRole', () => {
  613. beforeEach(() => {
  614. accessProfile.hasRole = vi.fn((role: string) => role === 'foo')
  615. })
  616. test('has role', () => {
  617. expect(abilityBuilder.hasRole('foo')).toBeTruthy()
  618. })
  619. test('has not role', () => {
  620. expect(abilityBuilder.hasRole('bar')).toBeFalsy()
  621. })
  622. })
  623. describe('hasAnyRole', () => {
  624. beforeEach(() => {
  625. accessProfile.hasRole = vi.fn(
  626. (role: string) => role === 'role1' || role === 'role2',
  627. )
  628. })
  629. test('own all roles', () => {
  630. expect(abilityBuilder.hasAnyRole(['role1', 'role2'])).toBeTruthy()
  631. })
  632. test('own at least one role', () => {
  633. expect(abilityBuilder.hasAnyRole(['role1', 'role3'])).toBeTruthy()
  634. })
  635. test('own none of the roles', () => {
  636. expect(abilityBuilder.hasAnyRole(['role3'])).toBeFalsy()
  637. })
  638. })
  639. describe('hasAllRoles', () => {
  640. beforeEach(() => {
  641. accessProfile.hasRole = vi.fn(
  642. (role: string) => role === 'role1' || role === 'role2',
  643. )
  644. })
  645. test('own all roles', () => {
  646. expect(abilityBuilder.hasAllRoles(['role1', 'role2'])).toBeTruthy()
  647. })
  648. test('own at least one role', () => {
  649. expect(abilityBuilder.hasAllRoles(['role1', 'role3'])).toBeFalsy()
  650. })
  651. test('own none of the roles', () => {
  652. expect(abilityBuilder.hasAllRoles(['role3'])).toBeFalsy()
  653. })
  654. })
  655. describe('hasModule', () => {
  656. beforeEach(() => {
  657. // @ts-expect-error accessing non-existent property for testing purposes
  658. organizationProfile.hasModule = vi.fn((module: string) => module === 'foo')
  659. })
  660. test('has module', () => {
  661. expect(abilityBuilder.hasModule('foo')).toBeTruthy()
  662. })
  663. test('has not module', () => {
  664. expect(abilityBuilder.hasModule('bar')).toBeFalsy()
  665. })
  666. })
  667. describe('hasAnyModule', () => {
  668. beforeEach(() => {
  669. // @ts-expect-error accessing non-existent property for testing purposes
  670. organizationProfile.hasModule = vi.fn(
  671. (Module: string) => Module === 'Module1' || Module === 'Module2',
  672. )
  673. })
  674. test('own all modules', () => {
  675. expect(abilityBuilder.hasAnyModule(['Module1', 'Module2'])).toBeTruthy()
  676. })
  677. test('own at least one module', () => {
  678. expect(abilityBuilder.hasAnyModule(['Module1', 'Module3'])).toBeTruthy()
  679. })
  680. test('own none of the modules', () => {
  681. expect(abilityBuilder.hasAnyModule(['Module3'])).toBeFalsy()
  682. })
  683. })
  684. describe('hasAllModules', () => {
  685. beforeEach(() => {
  686. // @ts-expect-error accessing non-existent property for testing purposes
  687. organizationProfile.hasModule = vi.fn(
  688. (Module: string) => Module === 'Module1' || Module === 'Module2',
  689. )
  690. })
  691. test('own all modules', () => {
  692. expect(abilityBuilder.hasAllModules(['Module1', 'Module2'])).toBeTruthy()
  693. })
  694. test('own at least one module', () => {
  695. expect(abilityBuilder.hasAllModules(['Module1', 'Module3'])).toBeFalsy()
  696. })
  697. test('own none of the modules', () => {
  698. expect(abilityBuilder.hasAllModules(['Module3'])).toBeFalsy()
  699. })
  700. })