abilityBuilder.test.ts 23 KB

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