abilityBuilder.test.ts 23 KB

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