UserMembershipController.test.mjs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. import { expect, vi, describe, it, beforeEach } from 'vitest'
  2. import MockRequest from '../helpers/MockRequestVitest.mjs'
  3. import MockResponse from '../helpers/MockResponseVitest.mjs'
  4. import EntityConfigs from '../../../../app/src/Features/UserMembership/UserMembershipEntityConfigs.js'
  5. import Errors from '../../../../app/src/Features/Errors/Errors.js'
  6. import UserMembershipErrors from '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs'
  7. const modulePath =
  8. '../../../../app/src/Features/UserMembership/UserMembershipController.mjs'
  9. vi.mock(
  10. '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs',
  11. () =>
  12. vi.importActual(
  13. '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs'
  14. )
  15. )
  16. vi.mock('../../../../app/src/Features/Errors/Errors.js', () =>
  17. vi.importActual('../../../../app/src/Features/Errors/Errors.js')
  18. )
  19. describe('UserMembershipController', () => {
  20. beforeEach(async ctx => {
  21. ctx.req = new MockRequest(vi)
  22. ctx.req.params.id = 'mock-entity-id'
  23. ctx.user = { _id: 'mock-user-id' }
  24. ctx.newUser = { _id: 'mock-new-user-id', email: 'new-user-email@foo.bar' }
  25. ctx.subscription = {
  26. _id: 'mock-subscription-id',
  27. admin_id: 'mock-admin-id',
  28. manager_ids: ['mock-admin-id'],
  29. fetchV1Data: vi.fn(callback => callback(null, ctx.subscription)),
  30. }
  31. ctx.institution = {
  32. _id: 'mock-institution-id',
  33. v1Id: 123,
  34. fetchV1Data: vi.fn(callback => {
  35. const institution = { ...ctx.institution }
  36. institution.name = 'Test Institution Name'
  37. callback(null, institution)
  38. }),
  39. managerIds: ['mock-member-id-1'],
  40. }
  41. ctx.users = [
  42. {
  43. _id: 'mock-member-id-1',
  44. email: 'mock-email-1@foo.com',
  45. last_logged_in_at: '2020-08-09T12:43:11.467Z',
  46. last_active_at: '2021-08-09T12:43:11.467Z',
  47. },
  48. {
  49. _id: 'mock-member-id-2',
  50. email: 'mock-email-2@foo.com',
  51. last_logged_in_at: '2020-05-20T10:41:11.407Z',
  52. last_active_at: '2021-05-20T10:41:11.407Z',
  53. },
  54. {
  55. _id: 'mock-member-id-3',
  56. email: 'mock-email-3@foo.com',
  57. last_logged_in_at: '2021-08-10T10:41:11.407Z',
  58. last_active_at: '2021-08-20T10:41:11.407Z',
  59. enrollment: {
  60. managedBy: 'some-other-subscription-id',
  61. enrolledAt: '2021-05-20T10:41:11.407Z',
  62. sso: undefined,
  63. },
  64. },
  65. {
  66. _id: 'mock-member-id-4',
  67. email: 'mock-email-4@foo.com',
  68. last_logged_in_at: '2021-01-01T10:41:11.407Z',
  69. last_active_at: '2021-01-02T10:41:11.407Z',
  70. enrollment: {
  71. managedBy: 'mock-subscription-id',
  72. enrolledAt: '2021-01-02T10:41:11.407Z',
  73. sso: undefined,
  74. },
  75. },
  76. {
  77. _id: 'mock-member-id-5',
  78. email: 'mock-email-5@foo.com',
  79. last_logged_in_at: '2023-01-01T10:41:11.407Z',
  80. last_active_at: '2023-01-02T10:41:11.407Z',
  81. enrollment: {
  82. sso: [{ groupId: ctx.subscription._id }],
  83. },
  84. },
  85. {
  86. _id: 'mock-member-id-6',
  87. email: 'mock-email-6@foo.com',
  88. last_logged_in_at: '2024-01-01T10:41:11.407Z',
  89. last_active_at: '2024-01-02T10:41:11.407Z',
  90. enrollment: {
  91. managedBy: 'mock-subscription-id',
  92. enrolledAt: '2024-01-02T10:41:11.407Z',
  93. sso: [{ groupId: ctx.subscription._id }],
  94. },
  95. },
  96. ]
  97. ctx.Settings = {
  98. managedUsers: {
  99. enabled: false,
  100. },
  101. }
  102. ctx.SessionManager = {
  103. getSessionUser: vi.fn().mockReturnValue(ctx.user),
  104. getLoggedInUserId: vi.fn().mockReturnValue(ctx.user._id),
  105. }
  106. ctx.SSOConfig = {
  107. findById: vi.fn().mockReturnValue({
  108. exec: vi.fn().mockResolvedValue({ enabled: true }),
  109. }),
  110. }
  111. ctx.UserMembershipHandler = {
  112. getEntity: vi.fn((_entity, _options, callback) =>
  113. callback(null, ctx.subscription)
  114. ),
  115. createEntity: vi.fn((_entity, _options, callback) =>
  116. callback(null, ctx.institution)
  117. ),
  118. getUsers: vi.fn((_entity, _options, callback) =>
  119. callback(null, ctx.users)
  120. ),
  121. addUser: vi.fn((_entity, _options, _email, callback) =>
  122. callback(null, ctx.newUser)
  123. ),
  124. removeUser: vi.fn((_entity, _options, _userId, callback) =>
  125. callback(null)
  126. ),
  127. promises: {
  128. getUsers: vi.fn().mockResolvedValue(ctx.users),
  129. addUser: vi.fn().mockResolvedValue(ctx.newUser),
  130. removeUser: vi.fn().mockResolvedValue(),
  131. createEntity: vi.fn().mockResolvedValue(ctx.institution),
  132. },
  133. }
  134. ctx.SplitTestHandler = {
  135. promises: {
  136. getAssignment: vi.fn().mockResolvedValue({ variant: 'default' }),
  137. },
  138. getAssignment: vi.fn((_testName, _userId, callback) =>
  139. callback(null, { variant: 'default' })
  140. ),
  141. }
  142. ctx.RecurlyClient = {
  143. promises: {
  144. getSubscription: vi.fn().mockResolvedValue({}),
  145. },
  146. }
  147. vi.doMock(
  148. '../../../../app/src/Features/Authentication/SessionManager',
  149. () => ({
  150. default: ctx.SessionManager,
  151. })
  152. )
  153. vi.doMock(
  154. '../../../../app/src/Features/SplitTests/SplitTestHandler',
  155. () => ({
  156. default: ctx.SplitTestHandler,
  157. })
  158. )
  159. vi.doMock(
  160. '../../../../app/src/Features/UserMembership/UserMembershipHandler',
  161. () => ({
  162. default: ctx.UserMembershipHandler,
  163. })
  164. )
  165. vi.doMock(
  166. '../../../../app/src/Features/Subscription/RecurlyClient',
  167. () => ({
  168. default: ctx.RecurlyClient,
  169. })
  170. )
  171. vi.doMock('@overleaf/settings', () => ({
  172. default: ctx.Settings,
  173. }))
  174. vi.doMock('../../../../app/src/models/SSOConfig', () => ({
  175. SSOConfig: ctx.SSOConfig,
  176. }))
  177. ctx.Modules = {
  178. promises: {
  179. hooks: {
  180. fire: vi.fn(),
  181. },
  182. },
  183. }
  184. vi.doMock('../../../../app/src/infrastructure/Modules.js', () => ({
  185. default: ctx.Modules,
  186. }))
  187. ctx.UserMembershipController = (await import(modulePath)).default
  188. })
  189. describe('index', () => {
  190. beforeEach(ctx => {
  191. ctx.req.user = ctx.user
  192. ctx.req.entity = ctx.subscription
  193. ctx.req.entityConfig = EntityConfigs.group
  194. ctx.Modules.promises.hooks.fire.mockResolvedValue([])
  195. })
  196. it('get users', async ({
  197. UserMembershipController,
  198. req,
  199. UserMembershipHandler,
  200. subscription,
  201. }) => {
  202. expect.assertions(1)
  203. await UserMembershipController.manageGroupMembers(req, {
  204. render: () => {
  205. expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
  206. subscription,
  207. {
  208. modelName: 'Subscription',
  209. baseQuery: { groupPlan: true },
  210. fields: {
  211. access: 'manager_ids',
  212. membership: 'member_ids',
  213. name: 'teamName',
  214. primaryKey: '_id',
  215. read: ['invited_emails', 'teamInvites', 'member_ids'],
  216. write: null,
  217. },
  218. hasMembersLimit: true,
  219. readOnly: true,
  220. }
  221. )
  222. },
  223. })
  224. })
  225. it('render group view', async ({
  226. UserMembershipController,
  227. req,
  228. subscription,
  229. users,
  230. }) => {
  231. expect.assertions(4)
  232. subscription.managedUsersEnabled = false
  233. await UserMembershipController.manageGroupMembers(req, {
  234. render: (viewPath, viewParams) => {
  235. expect(viewPath).to.equal('user_membership/group-members-react')
  236. expect(viewParams.users).to.deep.equal(users)
  237. expect(viewParams.groupSize).to.equal(subscription.membersLimit)
  238. expect(viewParams.managedUsersActive).to.equal(false)
  239. },
  240. })
  241. })
  242. it('render group view with managed users', async ({
  243. UserMembershipController,
  244. req,
  245. subscription,
  246. users,
  247. }) => {
  248. expect.assertions(5)
  249. subscription.managedUsersEnabled = true
  250. await UserMembershipController.manageGroupMembers(req, {
  251. render: (viewPath, viewParams) => {
  252. expect(viewPath).to.equal('user_membership/group-members-react')
  253. expect(viewParams.users).to.deep.equal(users)
  254. expect(viewParams.groupSize).to.equal(subscription.membersLimit)
  255. expect(viewParams.managedUsersActive).to.equal(true)
  256. expect(viewParams.isUserGroupManager).to.equal(false)
  257. },
  258. })
  259. })
  260. it('render group managers view', async ({
  261. UserMembershipController,
  262. req,
  263. user,
  264. }) => {
  265. expect.assertions(2)
  266. req.user = user
  267. req.entityConfig = EntityConfigs.groupManagers
  268. await UserMembershipController.manageGroupManagers(req, {
  269. render: (viewPath, viewParams) => {
  270. expect(viewPath).to.equal('user_membership/group-managers-react')
  271. expect(viewParams.groupSize).to.equal(undefined)
  272. },
  273. })
  274. })
  275. it('render institution view', async ({
  276. UserMembershipController,
  277. req,
  278. user,
  279. institution,
  280. }) => {
  281. expect.assertions(3)
  282. req.user = user
  283. req.entity = institution
  284. req.entityConfig = EntityConfigs.institution
  285. await UserMembershipController.manageInstitutionManagers(req, {
  286. render: (viewPath, viewParams) => {
  287. expect(viewPath).to.equal(
  288. 'user_membership/institution-managers-react'
  289. )
  290. expect(viewParams.name).to.equal('Test Institution Name')
  291. expect(viewParams.groupSize).to.equal(undefined)
  292. },
  293. })
  294. })
  295. })
  296. describe('add', () => {
  297. beforeEach(ctx => {
  298. ctx.req.body.email = ctx.newUser.email
  299. ctx.req.entity = ctx.subscription
  300. ctx.req.entityConfig = EntityConfigs.groupManagers
  301. })
  302. it('add user', async ({
  303. UserMembershipController,
  304. req,
  305. UserMembershipHandler,
  306. subscription,
  307. newUser,
  308. }) => {
  309. expect.assertions(1)
  310. await UserMembershipController.add(req, {
  311. json: () => {
  312. expect(UserMembershipHandler.promises.addUser).toHaveBeenCalledWith(
  313. subscription,
  314. {
  315. modelName: 'Subscription',
  316. baseQuery: { groupPlan: true },
  317. fields: {
  318. access: 'manager_ids',
  319. membership: 'member_ids',
  320. name: 'teamName',
  321. primaryKey: '_id',
  322. read: ['manager_ids'],
  323. write: 'manager_ids',
  324. },
  325. },
  326. newUser.email
  327. )
  328. },
  329. })
  330. })
  331. it('return user object', async ({
  332. UserMembershipController,
  333. req,
  334. newUser,
  335. }) => {
  336. expect.assertions(1)
  337. await UserMembershipController.add(req, {
  338. json: payload => {
  339. expect(payload.user).to.equal(newUser)
  340. },
  341. })
  342. })
  343. it('handle readOnly entity', async ({ UserMembershipController, req }) => {
  344. expect.assertions(2)
  345. req.entityConfig = EntityConfigs.group
  346. await UserMembershipController.add(req, null, error => {
  347. expect(error).to.exist
  348. expect(error).to.be.an.instanceof(Errors.NotFoundError)
  349. })
  350. })
  351. it('handle user already added', async ({
  352. UserMembershipController,
  353. req,
  354. UserMembershipHandler,
  355. }) => {
  356. expect.assertions(1)
  357. UserMembershipHandler.promises.addUser.mockRejectedValue(
  358. new UserMembershipErrors.UserAlreadyAddedError()
  359. )
  360. await UserMembershipController.add(
  361. req,
  362. {
  363. status: () => ({
  364. json: payload => {
  365. expect(payload.error.code).to.equal('user_already_added')
  366. },
  367. }),
  368. },
  369. () => {}
  370. )
  371. })
  372. it('handle user not found', async ({
  373. UserMembershipController,
  374. req,
  375. UserMembershipHandler,
  376. }) => {
  377. expect.assertions(1)
  378. UserMembershipHandler.promises.addUser.mockRejectedValue(
  379. new UserMembershipErrors.UserNotFoundError()
  380. )
  381. await UserMembershipController.add(req, {
  382. status: () => ({
  383. json: payload => {
  384. expect(payload.error.code).to.equal('user_not_found')
  385. },
  386. }),
  387. })
  388. })
  389. it('handle invalid email', async ({ UserMembershipController, req }) => {
  390. expect.assertions(1)
  391. req.body.email = 'not_valid_email'
  392. await UserMembershipController.add(req, {
  393. status: () => ({
  394. json: payload => {
  395. expect(payload.error.code).to.equal('invalid_email')
  396. },
  397. }),
  398. })
  399. })
  400. })
  401. describe('remove', () => {
  402. beforeEach(ctx => {
  403. ctx.req.params.userId = ctx.newUser._id
  404. ctx.req.entity = ctx.subscription
  405. ctx.req.entityConfig = EntityConfigs.groupManagers
  406. })
  407. it('remove user', async ({
  408. UserMembershipController,
  409. req,
  410. UserMembershipHandler,
  411. subscription,
  412. newUser,
  413. }) => {
  414. expect.assertions(1)
  415. await UserMembershipController.remove(req, {
  416. sendStatus: () => {
  417. expect(
  418. UserMembershipHandler.promises.removeUser
  419. ).toHaveBeenCalledWith(
  420. subscription,
  421. {
  422. modelName: 'Subscription',
  423. baseQuery: {
  424. groupPlan: true,
  425. },
  426. fields: {
  427. access: 'manager_ids',
  428. membership: 'member_ids',
  429. name: 'teamName',
  430. primaryKey: '_id',
  431. read: ['manager_ids'],
  432. write: 'manager_ids',
  433. },
  434. },
  435. newUser._id
  436. )
  437. },
  438. })
  439. })
  440. it('handle readOnly entity', async ({ UserMembershipController, req }) => {
  441. expect.assertions(2)
  442. req.entityConfig = EntityConfigs.group
  443. await UserMembershipController.remove(req, null, error => {
  444. expect(error).to.exist
  445. expect(error).to.be.an.instanceof(Errors.NotFoundError)
  446. })
  447. })
  448. it('prevent self removal', async ({
  449. UserMembershipController,
  450. req,
  451. user,
  452. }) => {
  453. expect.assertions(1)
  454. req.params.userId = user._id
  455. await UserMembershipController.remove(req, {
  456. status: () => ({
  457. json: payload => {
  458. expect(payload.error.code).to.equal('managers_cannot_remove_self')
  459. },
  460. }),
  461. })
  462. })
  463. it('prevent admin removal', async ({
  464. UserMembershipController,
  465. req,
  466. UserMembershipHandler,
  467. }) => {
  468. expect.assertions(1)
  469. UserMembershipHandler.promises.removeUser.mockRejectedValue(
  470. new UserMembershipErrors.UserIsManagerError()
  471. )
  472. await UserMembershipController.remove(req, {
  473. status: () => ({
  474. json: payload => {
  475. expect(payload.error.code).to.equal('managers_cannot_remove_admin')
  476. },
  477. }),
  478. })
  479. })
  480. })
  481. describe('exportCsv', () => {
  482. beforeEach(ctx => {
  483. ctx.req.entity = ctx.subscription
  484. ctx.req.entityConfig = EntityConfigs.groupManagers
  485. ctx.res = new MockResponse(vi)
  486. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  487. })
  488. it('get users', ({ UserMembershipHandler, subscription }) => {
  489. expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
  490. subscription,
  491. {
  492. modelName: 'Subscription',
  493. baseQuery: { groupPlan: true },
  494. fields: {
  495. access: 'manager_ids',
  496. membership: 'member_ids',
  497. name: 'teamName',
  498. primaryKey: '_id',
  499. read: ['manager_ids'],
  500. write: 'manager_ids',
  501. },
  502. }
  503. )
  504. })
  505. it('should set the correct content type on the request', ({ res }) => {
  506. expect(res.contentType).toHaveBeenCalledWith('text/csv; charset=utf-8')
  507. })
  508. it('should name the exported csv file', ({ res }) => {
  509. expect(res.header).toHaveBeenCalledWith(
  510. 'Content-Disposition',
  511. 'attachment; filename="Group.csv"'
  512. )
  513. })
  514. it('should export the correct csv', ({ res }) => {
  515. expect(res.send).toHaveBeenCalledWith(
  516. '"email","last_logged_in_at","last_active_at"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z"\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z"\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z"\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z"\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z"\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z"'
  517. )
  518. })
  519. })
  520. describe('exportCsv when group is managed', () => {
  521. beforeEach(ctx => {
  522. ctx.req.entity = Object.assign(
  523. { managedUsersEnabled: true },
  524. ctx.subscription
  525. )
  526. ctx.req.entityConfig = EntityConfigs.groupManagers
  527. ctx.res = new MockResponse(vi)
  528. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  529. })
  530. it('should export the correct csv', ({ res }) => {
  531. expect(res.send).toHaveBeenCalledWith(
  532. '"email","last_logged_in_at","last_active_at","managed"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z",false\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z",false\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z",false\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z",true\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z",false\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z",true'
  533. )
  534. })
  535. })
  536. describe('exportCsv when group has SSO', () => {
  537. beforeEach(ctx => {
  538. ctx.req.entity = Object.assign(
  539. { ssoConfig: 'sso-config-id' },
  540. ctx.subscription
  541. )
  542. ctx.req.entityConfig = EntityConfigs.groupManagers
  543. ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
  544. ctx.res = new MockResponse(vi)
  545. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  546. })
  547. it('should export the correct csv', ({ res }) => {
  548. expect(res.send).toHaveBeenCalledWith(
  549. '"email","last_logged_in_at","last_active_at","sso"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z",false\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z",false\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z",false\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z",false\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z",true\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z",true'
  550. )
  551. })
  552. })
  553. describe('exportCsv when group has SSO and managed users enabled', () => {
  554. beforeEach(ctx => {
  555. ctx.req.entity = Object.assign(
  556. { managedUsersEnabled: true },
  557. { ssoConfig: 'sso-config-id' },
  558. ctx.subscription
  559. )
  560. ctx.req.entityConfig = EntityConfigs.groupManagers
  561. ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
  562. ctx.res = new MockResponse(vi)
  563. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  564. })
  565. it('should export the correct csv', ({ res }) => {
  566. expect(res.send).toHaveBeenCalledWith(
  567. '"email","last_logged_in_at","last_active_at","managed","sso"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z",false,false\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z",false,false\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z",false,false\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z",true,false\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z",false,true\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z",true,true'
  568. )
  569. })
  570. })
  571. describe('new', () => {
  572. beforeEach(ctx => {
  573. ctx.req.params.name = 'publisher'
  574. ctx.req.params.id = 'abc'
  575. })
  576. it('renders view', async ({ UserMembershipController, req }) => {
  577. expect.assertions(2)
  578. await UserMembershipController.new(req, {
  579. render: (viewPath, data) => {
  580. expect(data.entityName).to.eq('publisher')
  581. expect(data.entityId).to.eq('abc')
  582. },
  583. })
  584. })
  585. })
  586. describe('create', () => {
  587. beforeEach(ctx => {
  588. ctx.req.params.name = 'institution'
  589. ctx.req.entityConfig = EntityConfigs.institution
  590. ctx.req.params.id = 123
  591. })
  592. it('creates institution', async ({
  593. UserMembershipController,
  594. req,
  595. UserMembershipHandler,
  596. }) => {
  597. expect.assertions(2)
  598. await UserMembershipController.create(req, {
  599. redirect: path => {
  600. expect(path).to.eq(EntityConfigs.institution.pathsFor(123).index)
  601. expect(
  602. UserMembershipHandler.promises.createEntity
  603. ).toHaveBeenCalledWith(123, {
  604. fields: {
  605. access: 'managerIds',
  606. membership: 'member_ids',
  607. name: 'name',
  608. primaryKey: 'v1Id',
  609. read: ['managerIds'],
  610. write: 'managerIds',
  611. },
  612. modelName: 'Institution',
  613. pathsFor: EntityConfigs.institution.pathsFor,
  614. })
  615. },
  616. })
  617. })
  618. })
  619. })