abilityBuilder.test.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  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. organizationProfile.getWebsite = 'https://example.com'
  388. expect(
  389. // @ts-expect-error accessing protected method for testing purposes
  390. abilityBuilder.execAndValidateCondition({
  391. function: 'organizationHasWebsite',
  392. }),
  393. ).toBeTruthy()
  394. organizationProfile.getWebsite = null
  395. expect(
  396. // @ts-expect-error accessing protected method for testing purposes
  397. abilityBuilder.execAndValidateCondition({
  398. function: 'organizationHasWebsite',
  399. }),
  400. ).toBeFalsy()
  401. })
  402. test('with expected result', () => {
  403. organizationProfile.getWebsite = 'https://example.com'
  404. expect(
  405. // @ts-expect-error accessing protected method for testing purposes
  406. abilityBuilder.execAndValidateCondition({
  407. function: 'organizationHasWebsite',
  408. expectedResult: true,
  409. }),
  410. ).toBeTruthy()
  411. expect(
  412. // @ts-expect-error accessing protected method for testing purposes
  413. abilityBuilder.execAndValidateCondition({
  414. function: 'organizationHasWebsite',
  415. // @ts-expect-error testing with intentionally wrong type
  416. expectedResult: 'abc',
  417. }),
  418. ).toBeFalsy()
  419. })
  420. test('invalid function', () => {
  421. expect(
  422. // @ts-expect-error accessing protected method for testing purposes
  423. () => abilityBuilder.execAndValidateCondition({ function: 'invalid' }),
  424. ).toThrowError('unknown condition function : invalid')
  425. })
  426. })
  427. describe('hasRoleAbility', () => {
  428. beforeEach(() => {
  429. ability.can = vi.fn((action: string, subject: string) => {
  430. return action === 'read' && subject === 'a_subject'
  431. })
  432. })
  433. test('owned ability', () => {
  434. expect(
  435. abilityBuilder.hasRoleAbility({
  436. action: ABILITIES.READ,
  437. subject: 'a_subject',
  438. }),
  439. ).toBeTruthy()
  440. })
  441. test('not owned ability', () => {
  442. expect(
  443. abilityBuilder.hasRoleAbility({
  444. action: ABILITIES.READ,
  445. subject: 'other_subject',
  446. }),
  447. ).toBeFalsy()
  448. })
  449. })
  450. describe('hasAllRoleAbilities', () => {
  451. beforeEach(() => {
  452. ability.can = vi.fn((action: string, subject: string) => {
  453. return (
  454. action === 'read' && (subject === 'subject1' || subject === 'subject2')
  455. )
  456. })
  457. })
  458. test('own all abilities', () => {
  459. const result = abilityBuilder.hasAllRoleAbilities([
  460. { action: ABILITIES.READ, subject: 'subject1' },
  461. { action: ABILITIES.READ, subject: 'subject2' },
  462. ])
  463. expect(result).toBeTruthy()
  464. })
  465. test('own at least one ability', () => {
  466. const result = abilityBuilder.hasAllRoleAbilities([
  467. { action: ABILITIES.READ, subject: 'subject1' },
  468. { action: ABILITIES.READ, subject: 'subject3' },
  469. ])
  470. expect(result).toBeFalsy()
  471. })
  472. test('own none of the abilities', () => {
  473. const result = abilityBuilder.hasAllRoleAbilities([
  474. { action: ABILITIES.READ, subject: 'subject3' },
  475. { action: ABILITIES.READ, subject: 'subject4' },
  476. ])
  477. expect(result).toBeFalsy()
  478. })
  479. })
  480. describe('hasAnyRoleAbility', () => {
  481. beforeEach(() => {
  482. ability.can = vi.fn((action: string, subject: string) => {
  483. return (
  484. action === 'read' && (subject === 'subject1' || subject === 'subject2')
  485. )
  486. })
  487. })
  488. test('has all abilities', () => {
  489. const result = abilityBuilder.hasAnyRoleAbility([
  490. { action: ABILITIES.READ, subject: 'subject1' },
  491. { action: ABILITIES.READ, subject: 'subject2' },
  492. ])
  493. expect(result).toBeTruthy()
  494. })
  495. test('has at least one ability', () => {
  496. const result = abilityBuilder.hasAnyRoleAbility([
  497. { action: ABILITIES.READ, subject: 'subject1' },
  498. { action: ABILITIES.READ, subject: 'subject3' },
  499. ])
  500. expect(result).toBeTruthy()
  501. })
  502. test('any none of the abilites', () => {
  503. const result = abilityBuilder.hasAnyRoleAbility([
  504. { action: ABILITIES.READ, subject: 'subject3' },
  505. { action: ABILITIES.READ, subject: 'subject4' },
  506. ])
  507. expect(result).toBeFalsy()
  508. })
  509. })
  510. describe('hasProfile', () => {
  511. test('owned profiles', () => {
  512. accessProfile.isAdmin = true
  513. accessProfile.isAdministratifManager = true
  514. accessProfile.isPedagogicManager = true
  515. accessProfile.isFinancialManager = true
  516. accessProfile.isCaMember = true
  517. accessProfile.isStudent = true
  518. accessProfile.isTeacher = true
  519. accessProfile.isMember = true
  520. accessProfile.isOther = true
  521. accessProfile.isGuardian = true
  522. accessProfile.isPayer = true
  523. expect(abilityBuilder.hasProfile('admin')).toBeTruthy()
  524. expect(abilityBuilder.hasProfile('administratifManager')).toBeTruthy()
  525. expect(abilityBuilder.hasProfile('pedagogicManager')).toBeTruthy()
  526. expect(abilityBuilder.hasProfile('financialManager')).toBeTruthy()
  527. expect(abilityBuilder.hasProfile('caMember')).toBeTruthy()
  528. expect(abilityBuilder.hasProfile('student')).toBeTruthy()
  529. expect(abilityBuilder.hasProfile('teacher')).toBeTruthy()
  530. expect(abilityBuilder.hasProfile('member')).toBeTruthy()
  531. expect(abilityBuilder.hasProfile('other')).toBeTruthy()
  532. expect(abilityBuilder.hasProfile('guardian')).toBeTruthy()
  533. expect(abilityBuilder.hasProfile('payor')).toBeTruthy()
  534. })
  535. test('not owned profiles', () => {
  536. accessProfile.isAdmin = false
  537. accessProfile.isAdministratifManager = false
  538. accessProfile.isPedagogicManager = false
  539. accessProfile.isFinancialManager = false
  540. accessProfile.isCaMember = false
  541. accessProfile.isStudent = false
  542. accessProfile.isTeacher = false
  543. accessProfile.isMember = false
  544. accessProfile.isOther = false
  545. accessProfile.isGuardian = false
  546. accessProfile.isPayer = false
  547. expect(abilityBuilder.hasProfile('admin')).toBeFalsy()
  548. expect(abilityBuilder.hasProfile('administratifManager')).toBeFalsy()
  549. expect(abilityBuilder.hasProfile('pedagogicManager')).toBeFalsy()
  550. expect(abilityBuilder.hasProfile('financialManager')).toBeFalsy()
  551. expect(abilityBuilder.hasProfile('caMember')).toBeFalsy()
  552. expect(abilityBuilder.hasProfile('student')).toBeFalsy()
  553. expect(abilityBuilder.hasProfile('teacher')).toBeFalsy()
  554. expect(abilityBuilder.hasProfile('member')).toBeFalsy()
  555. expect(abilityBuilder.hasProfile('other')).toBeFalsy()
  556. expect(abilityBuilder.hasProfile('guardian')).toBeFalsy()
  557. expect(abilityBuilder.hasProfile('payor')).toBeFalsy()
  558. })
  559. })
  560. describe('hasAnyProfile', () => {
  561. beforeEach(() => {
  562. accessProfile.isMember = true
  563. accessProfile.isGuardian = true
  564. accessProfile.isPayer = true
  565. })
  566. test('own all profiles', () => {
  567. expect(
  568. abilityBuilder.hasAnyProfile(['member', 'guardian', 'payor']),
  569. ).toBeTruthy()
  570. })
  571. test('own at least one profile', () => {
  572. expect(abilityBuilder.hasAnyProfile(['member', 'caMember'])).toBeTruthy()
  573. })
  574. test('own none of the profiles', () => {
  575. expect(
  576. abilityBuilder.hasAnyProfile(['caMember', 'isFinancialManager']),
  577. ).toBeFalsy()
  578. })
  579. })
  580. describe('hasAllProfiles', () => {
  581. beforeEach(() => {
  582. accessProfile.isMember = true
  583. accessProfile.isGuardian = true
  584. accessProfile.isPayer = true
  585. })
  586. test('own all profiles', () => {
  587. expect(
  588. abilityBuilder.hasAllProfiles(['member', 'guardian', 'payor']),
  589. ).toBeTruthy()
  590. })
  591. test('own only one of the profiles', () => {
  592. expect(abilityBuilder.hasAllProfiles(['member', 'caMember'])).toBeFalsy()
  593. })
  594. test('own none of the profiles', () => {
  595. expect(
  596. abilityBuilder.hasAllProfiles(['caMember', 'isFinancialManager']),
  597. ).toBeFalsy()
  598. })
  599. })
  600. describe('hasRole', () => {
  601. beforeEach(() => {
  602. accessProfile.hasRole = vi.fn((role: string) => role === 'foo')
  603. })
  604. test('has role', () => {
  605. expect(abilityBuilder.hasRole('foo')).toBeTruthy()
  606. })
  607. test('has not role', () => {
  608. expect(abilityBuilder.hasRole('bar')).toBeFalsy()
  609. })
  610. })
  611. describe('hasAnyRole', () => {
  612. beforeEach(() => {
  613. accessProfile.hasRole = vi.fn(
  614. (role: string) => role === 'role1' || role === 'role2',
  615. )
  616. })
  617. test('own all roles', () => {
  618. expect(abilityBuilder.hasAnyRole(['role1', 'role2'])).toBeTruthy()
  619. })
  620. test('own at least one role', () => {
  621. expect(abilityBuilder.hasAnyRole(['role1', 'role3'])).toBeTruthy()
  622. })
  623. test('own none of the roles', () => {
  624. expect(abilityBuilder.hasAnyRole(['role3'])).toBeFalsy()
  625. })
  626. })
  627. describe('hasAllRoles', () => {
  628. beforeEach(() => {
  629. accessProfile.hasRole = vi.fn(
  630. (role: string) => role === 'role1' || role === 'role2',
  631. )
  632. })
  633. test('own all roles', () => {
  634. expect(abilityBuilder.hasAllRoles(['role1', 'role2'])).toBeTruthy()
  635. })
  636. test('own at least one role', () => {
  637. expect(abilityBuilder.hasAllRoles(['role1', 'role3'])).toBeFalsy()
  638. })
  639. test('own none of the roles', () => {
  640. expect(abilityBuilder.hasAllRoles(['role3'])).toBeFalsy()
  641. })
  642. })
  643. describe('hasModule', () => {
  644. beforeEach(() => {
  645. // @ts-expect-error accessing non-existent property for testing purposes
  646. organizationProfile.hasModule = vi.fn((module: string) => module === 'foo')
  647. })
  648. test('has module', () => {
  649. expect(abilityBuilder.hasModule('foo')).toBeTruthy()
  650. })
  651. test('has not module', () => {
  652. expect(abilityBuilder.hasModule('bar')).toBeFalsy()
  653. })
  654. })
  655. describe('hasAnyModule', () => {
  656. beforeEach(() => {
  657. // @ts-expect-error accessing non-existent property for testing purposes
  658. organizationProfile.hasModule = vi.fn(
  659. (Module: string) => Module === 'Module1' || Module === 'Module2',
  660. )
  661. })
  662. test('own all modules', () => {
  663. expect(abilityBuilder.hasAnyModule(['Module1', 'Module2'])).toBeTruthy()
  664. })
  665. test('own at least one module', () => {
  666. expect(abilityBuilder.hasAnyModule(['Module1', 'Module3'])).toBeTruthy()
  667. })
  668. test('own none of the modules', () => {
  669. expect(abilityBuilder.hasAnyModule(['Module3'])).toBeFalsy()
  670. })
  671. })
  672. describe('hasAllModules', () => {
  673. beforeEach(() => {
  674. // @ts-expect-error accessing non-existent property for testing purposes
  675. organizationProfile.hasModule = vi.fn(
  676. (Module: string) => Module === 'Module1' || Module === 'Module2',
  677. )
  678. })
  679. test('own all modules', () => {
  680. expect(abilityBuilder.hasAllModules(['Module1', 'Module2'])).toBeTruthy()
  681. })
  682. test('own at least one module', () => {
  683. expect(abilityBuilder.hasAllModules(['Module1', 'Module3'])).toBeFalsy()
  684. })
  685. test('own none of the modules', () => {
  686. expect(abilityBuilder.hasAllModules(['Module3'])).toBeFalsy()
  687. })
  688. })