UserMembershipController.test.mjs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. plans: [
  102. {
  103. planCode: 'personal',
  104. name: 'Personal',
  105. price_in_cents: 0,
  106. features: {
  107. collaborators: -1,
  108. dropbox: true,
  109. github: true,
  110. gitBridge: true,
  111. versioning: true,
  112. compileTimeout: 180,
  113. compileGroup: 'standard',
  114. references: true,
  115. trackChanges: true,
  116. },
  117. },
  118. ],
  119. }
  120. ctx.SessionManager = {
  121. getSessionUser: vi.fn().mockReturnValue(ctx.user),
  122. getLoggedInUserId: vi.fn().mockReturnValue(ctx.user._id),
  123. }
  124. ctx.SSOConfig = {
  125. findById: vi.fn().mockReturnValue({
  126. exec: vi.fn().mockResolvedValue({ enabled: true }),
  127. }),
  128. }
  129. ctx.UserMembershipHandler = {
  130. getEntity: vi.fn((_entity, _options, callback) =>
  131. callback(null, ctx.subscription)
  132. ),
  133. createEntity: vi.fn((_entity, _options, callback) =>
  134. callback(null, ctx.institution)
  135. ),
  136. getUsers: vi.fn((_entity, _options, callback) =>
  137. callback(null, ctx.users)
  138. ),
  139. addUser: vi.fn((_entity, _options, _email, callback) =>
  140. callback(null, ctx.newUser)
  141. ),
  142. removeUser: vi.fn((_entity, _options, _userId, callback) =>
  143. callback(null)
  144. ),
  145. promises: {
  146. getUsers: vi.fn().mockResolvedValue(ctx.users),
  147. addUser: vi.fn().mockResolvedValue(ctx.newUser),
  148. removeUser: vi.fn().mockResolvedValue(),
  149. createEntity: vi.fn().mockResolvedValue(ctx.institution),
  150. },
  151. }
  152. ctx.SplitTestHandler = {
  153. promises: {
  154. getAssignment: vi.fn().mockResolvedValue({ variant: 'default' }),
  155. },
  156. getAssignment: vi.fn((_testName, _userId, callback) =>
  157. callback(null, { variant: 'default' })
  158. ),
  159. }
  160. ctx.RecurlyClient = {
  161. promises: {
  162. getSubscription: vi.fn().mockResolvedValue({}),
  163. },
  164. }
  165. vi.doMock(
  166. '../../../../app/src/Features/Authentication/SessionManager',
  167. () => ({
  168. default: ctx.SessionManager,
  169. })
  170. )
  171. vi.doMock(
  172. '../../../../app/src/Features/SplitTests/SplitTestHandler',
  173. () => ({
  174. default: ctx.SplitTestHandler,
  175. })
  176. )
  177. vi.doMock(
  178. '../../../../app/src/Features/UserMembership/UserMembershipHandler',
  179. () => ({
  180. default: ctx.UserMembershipHandler,
  181. })
  182. )
  183. vi.doMock(
  184. '../../../../app/src/Features/Subscription/RecurlyClient',
  185. () => ({
  186. default: ctx.RecurlyClient,
  187. })
  188. )
  189. vi.doMock('@overleaf/settings', () => ({
  190. default: ctx.Settings,
  191. }))
  192. vi.doMock('../../../../app/src/models/SSOConfig', () => ({
  193. SSOConfig: ctx.SSOConfig,
  194. }))
  195. ctx.Modules = {
  196. promises: {
  197. hooks: {
  198. fire: vi.fn(),
  199. },
  200. },
  201. }
  202. vi.doMock('../../../../app/src/infrastructure/Modules.js', () => ({
  203. default: ctx.Modules,
  204. }))
  205. ctx.UserMembershipController = (await import(modulePath)).default
  206. })
  207. describe('index', () => {
  208. beforeEach(ctx => {
  209. ctx.req.user = ctx.user
  210. ctx.req.entity = ctx.subscription
  211. ctx.req.entityConfig = EntityConfigs.group
  212. ctx.Modules.promises.hooks.fire.mockResolvedValue([])
  213. })
  214. it('get users', async ({
  215. UserMembershipController,
  216. req,
  217. UserMembershipHandler,
  218. subscription,
  219. }) => {
  220. expect.assertions(1)
  221. await UserMembershipController.manageGroupMembers(req, {
  222. render: () => {
  223. expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
  224. subscription,
  225. {
  226. modelName: 'Subscription',
  227. baseQuery: { groupPlan: true },
  228. fields: {
  229. access: 'manager_ids',
  230. membership: 'member_ids',
  231. name: 'teamName',
  232. primaryKey: '_id',
  233. read: ['invited_emails', 'teamInvites', 'member_ids'],
  234. write: null,
  235. },
  236. hasMembersLimit: true,
  237. readOnly: true,
  238. }
  239. )
  240. },
  241. })
  242. })
  243. it('render group view', async ({
  244. UserMembershipController,
  245. req,
  246. subscription,
  247. users,
  248. }) => {
  249. expect.assertions(4)
  250. subscription.managedUsersEnabled = false
  251. await UserMembershipController.manageGroupMembers(req, {
  252. render: (viewPath, viewParams) => {
  253. expect(viewPath).to.equal('user_membership/group-members-react')
  254. expect(viewParams.users).to.deep.equal(users)
  255. expect(viewParams.groupSize).to.equal(subscription.membersLimit)
  256. expect(viewParams.managedUsersActive).to.equal(false)
  257. },
  258. })
  259. })
  260. it('render group view with managed users', async ({
  261. UserMembershipController,
  262. req,
  263. subscription,
  264. users,
  265. }) => {
  266. expect.assertions(5)
  267. subscription.managedUsersEnabled = true
  268. await UserMembershipController.manageGroupMembers(req, {
  269. render: (viewPath, viewParams) => {
  270. expect(viewPath).to.equal('user_membership/group-members-react')
  271. expect(viewParams.users).to.deep.equal(users)
  272. expect(viewParams.groupSize).to.equal(subscription.membersLimit)
  273. expect(viewParams.managedUsersActive).to.equal(true)
  274. expect(viewParams.isUserGroupManager).to.equal(false)
  275. },
  276. })
  277. })
  278. it('render group managers view', async ({
  279. UserMembershipController,
  280. req,
  281. user,
  282. }) => {
  283. expect.assertions(2)
  284. req.user = user
  285. req.entityConfig = EntityConfigs.groupManagers
  286. await UserMembershipController.manageGroupManagers(req, {
  287. render: (viewPath, viewParams) => {
  288. expect(viewPath).to.equal('user_membership/group-managers-react')
  289. expect(viewParams.groupSize).to.equal(undefined)
  290. },
  291. })
  292. })
  293. it('render institution view', async ({
  294. UserMembershipController,
  295. req,
  296. user,
  297. institution,
  298. }) => {
  299. expect.assertions(3)
  300. req.user = user
  301. req.entity = institution
  302. req.entityConfig = EntityConfigs.institution
  303. await UserMembershipController.manageInstitutionManagers(req, {
  304. render: (viewPath, viewParams) => {
  305. expect(viewPath).to.equal(
  306. 'user_membership/institution-managers-react'
  307. )
  308. expect(viewParams.name).to.equal('Test Institution Name')
  309. expect(viewParams.groupSize).to.equal(undefined)
  310. },
  311. })
  312. })
  313. })
  314. describe('add', () => {
  315. beforeEach(ctx => {
  316. ctx.req.body.email = ctx.newUser.email
  317. ctx.req.entity = ctx.subscription
  318. ctx.req.entityConfig = EntityConfigs.groupManagers
  319. })
  320. it('add user', async ({
  321. UserMembershipController,
  322. req,
  323. UserMembershipHandler,
  324. subscription,
  325. newUser,
  326. }) => {
  327. expect.assertions(1)
  328. await UserMembershipController.add(req, {
  329. json: () => {
  330. expect(UserMembershipHandler.promises.addUser).toHaveBeenCalledWith(
  331. subscription,
  332. {
  333. modelName: 'Subscription',
  334. baseQuery: { groupPlan: true },
  335. fields: {
  336. access: 'manager_ids',
  337. membership: 'member_ids',
  338. name: 'teamName',
  339. primaryKey: '_id',
  340. read: ['manager_ids'],
  341. write: 'manager_ids',
  342. },
  343. },
  344. newUser.email
  345. )
  346. },
  347. })
  348. })
  349. it('return user object', async ({
  350. UserMembershipController,
  351. req,
  352. newUser,
  353. }) => {
  354. expect.assertions(1)
  355. await UserMembershipController.add(req, {
  356. json: payload => {
  357. expect(payload.user).to.equal(newUser)
  358. },
  359. })
  360. })
  361. it('handle readOnly entity', async ({ UserMembershipController, req }) => {
  362. expect.assertions(2)
  363. req.entityConfig = EntityConfigs.group
  364. await UserMembershipController.add(req, null, error => {
  365. expect(error).to.exist
  366. expect(error).to.be.an.instanceof(Errors.NotFoundError)
  367. })
  368. })
  369. it('handle user already added', async ({
  370. UserMembershipController,
  371. req,
  372. UserMembershipHandler,
  373. }) => {
  374. expect.assertions(1)
  375. UserMembershipHandler.promises.addUser.mockRejectedValue(
  376. new UserMembershipErrors.UserAlreadyAddedError()
  377. )
  378. await UserMembershipController.add(
  379. req,
  380. {
  381. status: () => ({
  382. json: payload => {
  383. expect(payload.error.code).to.equal('user_already_added')
  384. },
  385. }),
  386. },
  387. () => {}
  388. )
  389. })
  390. it('handle user not found', async ({
  391. UserMembershipController,
  392. req,
  393. UserMembershipHandler,
  394. }) => {
  395. expect.assertions(1)
  396. UserMembershipHandler.promises.addUser.mockRejectedValue(
  397. new UserMembershipErrors.UserNotFoundError()
  398. )
  399. await UserMembershipController.add(req, {
  400. status: () => ({
  401. json: payload => {
  402. expect(payload.error.code).to.equal('user_not_found')
  403. },
  404. }),
  405. })
  406. })
  407. it('handle invalid email', async ({ UserMembershipController, req }) => {
  408. expect.assertions(1)
  409. req.body.email = 'not_valid_email'
  410. await UserMembershipController.add(req, {
  411. status: () => ({
  412. json: payload => {
  413. expect(payload.error.code).to.equal('invalid_email')
  414. },
  415. }),
  416. })
  417. })
  418. })
  419. describe('remove', () => {
  420. beforeEach(ctx => {
  421. ctx.req.params.userId = ctx.newUser._id
  422. ctx.req.entity = ctx.subscription
  423. ctx.req.entityConfig = EntityConfigs.groupManagers
  424. })
  425. it('remove user', async ({
  426. UserMembershipController,
  427. req,
  428. UserMembershipHandler,
  429. subscription,
  430. newUser,
  431. }) => {
  432. expect.assertions(1)
  433. await UserMembershipController.remove(req, {
  434. sendStatus: () => {
  435. expect(
  436. UserMembershipHandler.promises.removeUser
  437. ).toHaveBeenCalledWith(
  438. subscription,
  439. {
  440. modelName: 'Subscription',
  441. baseQuery: {
  442. groupPlan: true,
  443. },
  444. fields: {
  445. access: 'manager_ids',
  446. membership: 'member_ids',
  447. name: 'teamName',
  448. primaryKey: '_id',
  449. read: ['manager_ids'],
  450. write: 'manager_ids',
  451. },
  452. },
  453. newUser._id
  454. )
  455. },
  456. })
  457. })
  458. it('handle readOnly entity', async ({ UserMembershipController, req }) => {
  459. expect.assertions(2)
  460. req.entityConfig = EntityConfigs.group
  461. await UserMembershipController.remove(req, null, error => {
  462. expect(error).to.exist
  463. expect(error).to.be.an.instanceof(Errors.NotFoundError)
  464. })
  465. })
  466. it('prevent self removal', async ({
  467. UserMembershipController,
  468. req,
  469. user,
  470. }) => {
  471. expect.assertions(1)
  472. req.params.userId = user._id
  473. await UserMembershipController.remove(req, {
  474. status: () => ({
  475. json: payload => {
  476. expect(payload.error.code).to.equal('managers_cannot_remove_self')
  477. },
  478. }),
  479. })
  480. })
  481. it('prevent admin removal', async ({
  482. UserMembershipController,
  483. req,
  484. UserMembershipHandler,
  485. }) => {
  486. expect.assertions(1)
  487. UserMembershipHandler.promises.removeUser.mockRejectedValue(
  488. new UserMembershipErrors.UserIsManagerError()
  489. )
  490. await UserMembershipController.remove(req, {
  491. status: () => ({
  492. json: payload => {
  493. expect(payload.error.code).to.equal('managers_cannot_remove_admin')
  494. },
  495. }),
  496. })
  497. })
  498. })
  499. describe('exportCsv', () => {
  500. beforeEach(ctx => {
  501. ctx.req.entity = ctx.subscription
  502. ctx.req.entityConfig = EntityConfigs.groupManagers
  503. ctx.res = new MockResponse(vi)
  504. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  505. })
  506. it('get users', ({ UserMembershipHandler, subscription }) => {
  507. expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
  508. subscription,
  509. {
  510. modelName: 'Subscription',
  511. baseQuery: { groupPlan: true },
  512. fields: {
  513. access: 'manager_ids',
  514. membership: 'member_ids',
  515. name: 'teamName',
  516. primaryKey: '_id',
  517. read: ['manager_ids'],
  518. write: 'manager_ids',
  519. },
  520. }
  521. )
  522. })
  523. it('should set the correct content type on the request', ({ res }) => {
  524. expect(res.contentType).toHaveBeenCalledWith('text/csv; charset=utf-8')
  525. })
  526. it('should name the exported csv file', ({ res }) => {
  527. expect(res.header).toHaveBeenCalledWith(
  528. 'Content-Disposition',
  529. 'attachment; filename="Group.csv"'
  530. )
  531. })
  532. it('should export the correct csv', ({ res }) => {
  533. expect(res.send).toHaveBeenCalledWith(
  534. '"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"'
  535. )
  536. })
  537. })
  538. describe('exportCsv when group is managed', () => {
  539. beforeEach(ctx => {
  540. ctx.req.entity = Object.assign(
  541. { managedUsersEnabled: true },
  542. ctx.subscription
  543. )
  544. ctx.req.entityConfig = EntityConfigs.groupManagers
  545. ctx.res = new MockResponse(vi)
  546. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  547. })
  548. it('should export the correct csv', ({ res }) => {
  549. expect(res.send).toHaveBeenCalledWith(
  550. '"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'
  551. )
  552. })
  553. })
  554. describe('exportCsv when group has SSO', () => {
  555. beforeEach(ctx => {
  556. ctx.req.entity = Object.assign(
  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","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'
  568. )
  569. })
  570. })
  571. describe('exportCsv when group has SSO and managed users enabled', () => {
  572. beforeEach(ctx => {
  573. ctx.req.entity = Object.assign(
  574. { managedUsersEnabled: true },
  575. { ssoConfig: 'sso-config-id' },
  576. ctx.subscription
  577. )
  578. ctx.req.entityConfig = EntityConfigs.groupManagers
  579. ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
  580. ctx.res = new MockResponse(vi)
  581. ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
  582. })
  583. it('should export the correct csv', ({ res }) => {
  584. expect(res.send).toHaveBeenCalledWith(
  585. '"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'
  586. )
  587. })
  588. })
  589. describe('new', () => {
  590. beforeEach(ctx => {
  591. ctx.req.params.name = 'publisher'
  592. ctx.req.params.id = 'abc'
  593. })
  594. it('renders view', async ({ UserMembershipController, req }) => {
  595. expect.assertions(2)
  596. await UserMembershipController.new(req, {
  597. render: (viewPath, data) => {
  598. expect(data.entityName).to.eq('publisher')
  599. expect(data.entityId).to.eq('abc')
  600. },
  601. })
  602. })
  603. })
  604. describe('create', () => {
  605. beforeEach(ctx => {
  606. ctx.req.params.name = 'institution'
  607. ctx.req.entityConfig = EntityConfigs.institution
  608. ctx.req.params.id = 123
  609. })
  610. it('creates institution', async ({
  611. UserMembershipController,
  612. req,
  613. UserMembershipHandler,
  614. }) => {
  615. expect.assertions(2)
  616. await UserMembershipController.create(req, {
  617. redirect: path => {
  618. expect(path).to.eq(EntityConfigs.institution.pathsFor(123).index)
  619. expect(
  620. UserMembershipHandler.promises.createEntity
  621. ).toHaveBeenCalledWith(123, {
  622. fields: {
  623. access: 'managerIds',
  624. membership: 'member_ids',
  625. name: 'name',
  626. primaryKey: 'v1Id',
  627. read: ['managerIds'],
  628. write: 'managerIds',
  629. },
  630. modelName: 'Institution',
  631. pathsFor: EntityConfigs.institution.pathsFor,
  632. })
  633. },
  634. })
  635. })
  636. })
  637. })