abilityBuilder.test.ts 24 KB

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