mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-25 02:00:10 +02:00
* preserve pending changes when generating change requests * re-apply pending term_end changes after immediate updates * block changes when Stripe subscription has multiple phases * handle MultiplePendingChangesError & rm PendingChangeError GitOrigin-RevId: 0af11044766ff48e683d684ad6d62b732d17290c
819 lines
26 KiB
JavaScript
819 lines
26 KiB
JavaScript
import { expect, vi, describe, it, beforeEach } from 'vitest'
|
|
import MockRequest from '../helpers/MockRequest.mjs'
|
|
import MockResponse from '../helpers/MockResponse.mjs'
|
|
import EntityConfigs from '../../../../app/src/Features/UserMembership/UserMembershipEntityConfigs.mjs'
|
|
import Errors from '../../../../app/src/Features/Errors/Errors.js'
|
|
import UserMembershipErrors from '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs'
|
|
|
|
const modulePath =
|
|
'../../../../app/src/Features/UserMembership/UserMembershipController.mjs'
|
|
|
|
vi.mock(
|
|
'../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs',
|
|
() =>
|
|
vi.importActual(
|
|
'../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs'
|
|
)
|
|
)
|
|
|
|
vi.mock('../../../../app/src/Features/Errors/Errors.js', () =>
|
|
vi.importActual('../../../../app/src/Features/Errors/Errors.js')
|
|
)
|
|
|
|
describe('UserMembershipController', () => {
|
|
let recurlySubscriptionId
|
|
|
|
beforeEach(async ctx => {
|
|
recurlySubscriptionId = 'mock-recurly-subscription-id'
|
|
ctx.req = new MockRequest(vi)
|
|
ctx.req.params.id = 'mock-entity-id'
|
|
ctx.user = { _id: 'mock-user-id' }
|
|
ctx.newUser = { _id: 'mock-new-user-id', email: 'new-user-email@foo.bar' }
|
|
ctx.subscription = {
|
|
_id: 'mock-subscription-id',
|
|
admin_id: 'mock-admin-id',
|
|
manager_ids: ['mock-admin-id'],
|
|
planCode: 'group_professional',
|
|
recurlySubscription_id: recurlySubscriptionId,
|
|
fetchV1Data: vi.fn(callback => callback(null, ctx.subscription)),
|
|
}
|
|
ctx.institution = {
|
|
_id: 'mock-institution-id',
|
|
v1Id: 123,
|
|
fetchV1Data: vi.fn(callback => {
|
|
const institution = { ...ctx.institution }
|
|
institution.name = 'Test Institution Name'
|
|
callback(null, institution)
|
|
}),
|
|
managerIds: ['mock-member-id-1'],
|
|
}
|
|
ctx.users = [
|
|
{
|
|
_id: 'mock-member-id-1',
|
|
email: 'mock-email-1@foo.com',
|
|
last_logged_in_at: '2020-08-09T12:43:11.467Z',
|
|
last_active_at: '2021-08-09T12:43:11.467Z',
|
|
},
|
|
{
|
|
_id: 'mock-member-id-2',
|
|
email: 'mock-email-2@foo.com',
|
|
last_logged_in_at: '2020-05-20T10:41:11.407Z',
|
|
last_active_at: '2021-05-20T10:41:11.407Z',
|
|
},
|
|
{
|
|
_id: 'mock-member-id-3',
|
|
email: 'mock-email-3@foo.com',
|
|
last_logged_in_at: '2021-08-10T10:41:11.407Z',
|
|
last_active_at: '2021-08-20T10:41:11.407Z',
|
|
enrollment: {
|
|
managedBy: 'some-other-subscription-id',
|
|
enrolledAt: '2021-05-20T10:41:11.407Z',
|
|
sso: undefined,
|
|
},
|
|
},
|
|
{
|
|
_id: 'mock-member-id-4',
|
|
email: 'mock-email-4@foo.com',
|
|
last_logged_in_at: '2021-01-01T10:41:11.407Z',
|
|
last_active_at: '2021-01-02T10:41:11.407Z',
|
|
enrollment: {
|
|
managedBy: 'mock-subscription-id',
|
|
enrolledAt: '2021-01-02T10:41:11.407Z',
|
|
sso: undefined,
|
|
},
|
|
},
|
|
{
|
|
_id: 'mock-member-id-5',
|
|
email: 'mock-email-5@foo.com',
|
|
last_logged_in_at: '2023-01-01T10:41:11.407Z',
|
|
last_active_at: '2023-01-02T10:41:11.407Z',
|
|
enrollment: {
|
|
sso: [{ groupId: ctx.subscription._id }],
|
|
},
|
|
},
|
|
{
|
|
_id: 'mock-member-id-6',
|
|
email: 'mock-email-6@foo.com',
|
|
last_logged_in_at: '2024-01-01T10:41:11.407Z',
|
|
last_active_at: '2024-01-02T10:41:11.407Z',
|
|
enrollment: {
|
|
managedBy: 'mock-subscription-id',
|
|
enrolledAt: '2024-01-02T10:41:11.407Z',
|
|
sso: [{ groupId: ctx.subscription._id }],
|
|
},
|
|
},
|
|
]
|
|
|
|
ctx.Settings = {
|
|
managedUsers: {
|
|
enabled: false,
|
|
},
|
|
plans: [
|
|
{
|
|
planCode: 'personal',
|
|
name: 'Personal',
|
|
price_in_cents: 0,
|
|
features: {
|
|
collaborators: -1,
|
|
dropbox: true,
|
|
github: true,
|
|
gitBridge: true,
|
|
versioning: true,
|
|
compileTimeout: 180,
|
|
compileGroup: 'standard',
|
|
references: true,
|
|
trackChanges: true,
|
|
},
|
|
},
|
|
],
|
|
}
|
|
|
|
ctx.SessionManager = {
|
|
getSessionUser: vi.fn().mockReturnValue(ctx.user),
|
|
getLoggedInUserId: vi.fn().mockReturnValue(ctx.user._id),
|
|
}
|
|
ctx.SSOConfig = {
|
|
findById: vi.fn().mockReturnValue({
|
|
exec: vi.fn().mockResolvedValue({ enabled: true }),
|
|
}),
|
|
}
|
|
ctx.UserMembershipHandler = {
|
|
getEntity: vi.fn((_entity, _options, callback) =>
|
|
callback(null, ctx.subscription)
|
|
),
|
|
createEntity: vi.fn((_entity, _options, callback) =>
|
|
callback(null, ctx.institution)
|
|
),
|
|
getUsers: vi.fn((_entity, _options, callback) =>
|
|
callback(null, ctx.users)
|
|
),
|
|
addUser: vi.fn((_entity, _options, _email, callback) =>
|
|
callback(null, ctx.newUser)
|
|
),
|
|
removeUser: vi.fn((_entity, _options, _userId, callback) =>
|
|
callback(null)
|
|
),
|
|
promises: {
|
|
getUsers: vi.fn().mockResolvedValue(ctx.users),
|
|
addUser: vi.fn().mockResolvedValue(ctx.newUser),
|
|
removeUser: vi.fn().mockResolvedValue(),
|
|
createEntity: vi.fn().mockResolvedValue(ctx.institution),
|
|
},
|
|
}
|
|
ctx.SplitTestHandler = {
|
|
promises: {
|
|
getAssignment: vi.fn().mockResolvedValue({ variant: 'default' }),
|
|
},
|
|
getAssignment: vi.fn((_testName, _userId, callback) =>
|
|
callback(null, { variant: 'default' })
|
|
),
|
|
}
|
|
ctx.RecurlyClient = {
|
|
promises: {
|
|
getSubscription: vi.fn().mockResolvedValue({
|
|
id: recurlySubscriptionId,
|
|
}),
|
|
},
|
|
}
|
|
|
|
ctx.PlansLocator = {
|
|
findLocalPlanInSettings: vi.fn().mockReturnValue({
|
|
planCode: 'group_professional',
|
|
canUseFlexibleLicensing: true,
|
|
}),
|
|
}
|
|
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Authentication/SessionManager',
|
|
() => ({
|
|
default: ctx.SessionManager,
|
|
})
|
|
)
|
|
|
|
vi.doMock(
|
|
'../../../../app/src/Features/SplitTests/SplitTestHandler',
|
|
() => ({
|
|
default: ctx.SplitTestHandler,
|
|
})
|
|
)
|
|
|
|
vi.doMock(
|
|
'../../../../app/src/Features/UserMembership/UserMembershipHandler',
|
|
() => ({
|
|
default: ctx.UserMembershipHandler,
|
|
})
|
|
)
|
|
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Subscription/RecurlyClient',
|
|
() => ({
|
|
default: ctx.RecurlyClient,
|
|
})
|
|
)
|
|
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Subscription/PlansLocator.mjs',
|
|
() => ({
|
|
default: ctx.PlansLocator,
|
|
})
|
|
)
|
|
|
|
vi.doMock('@overleaf/settings', () => ({
|
|
default: ctx.Settings,
|
|
}))
|
|
|
|
vi.doMock('../../../../app/src/models/SSOConfig', () => ({
|
|
SSOConfig: ctx.SSOConfig,
|
|
}))
|
|
|
|
ctx.Modules = {
|
|
promises: {
|
|
hooks: {
|
|
fire: vi.fn(),
|
|
},
|
|
},
|
|
}
|
|
vi.doMock('../../../../app/src/infrastructure/Modules.mjs', () => ({
|
|
default: ctx.Modules,
|
|
}))
|
|
|
|
ctx.UserMembershipController = (await import(modulePath)).default
|
|
})
|
|
|
|
describe('index', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.user = ctx.user
|
|
ctx.req.entity = ctx.subscription
|
|
ctx.req.entityConfig = EntityConfigs.group
|
|
ctx.Modules.promises.hooks.fire.mockResolvedValue([])
|
|
})
|
|
|
|
it('get users', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
subscription,
|
|
}) => {
|
|
expect.assertions(1)
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: () => {
|
|
expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
|
|
subscription,
|
|
{
|
|
modelName: 'Subscription',
|
|
baseQuery: { groupPlan: true },
|
|
fields: {
|
|
access: 'manager_ids',
|
|
membership: 'member_ids',
|
|
name: 'teamName',
|
|
primaryKey: '_id',
|
|
read: ['invited_emails', 'teamInvites', 'member_ids'],
|
|
write: null,
|
|
},
|
|
hasMembersLimit: true,
|
|
readOnly: true,
|
|
}
|
|
)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('render group view', async ({
|
|
UserMembershipController,
|
|
req,
|
|
subscription,
|
|
users,
|
|
}) => {
|
|
expect.assertions(4)
|
|
subscription.managedUsersEnabled = false
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewPath).to.equal('user_membership/group-members-react')
|
|
expect(viewParams.users).to.deep.equal(users)
|
|
expect(viewParams.groupSize).to.equal(subscription.membersLimit)
|
|
expect(viewParams.managedUsersActive).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('render group view with managed users', async ({
|
|
UserMembershipController,
|
|
req,
|
|
subscription,
|
|
users,
|
|
}) => {
|
|
expect.assertions(5)
|
|
subscription.managedUsersEnabled = true
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewPath).to.equal('user_membership/group-members-react')
|
|
expect(viewParams.users).to.deep.equal(users)
|
|
expect(viewParams.groupSize).to.equal(subscription.membersLimit)
|
|
expect(viewParams.managedUsersActive).to.equal(true)
|
|
expect(viewParams.isUserGroupManager).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
|
|
describe('canUseAddSeatsFeature', () => {
|
|
beforeEach(ctx => {
|
|
ctx.subscription.admin_id = 'mock-admin-id'
|
|
ctx.SessionManager.getLoggedInUserId.mockReturnValue('mock-admin-id')
|
|
})
|
|
|
|
it('should be true when all conditions are met', async ({
|
|
UserMembershipController,
|
|
req,
|
|
}) => {
|
|
expect.assertions(1)
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(true)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should be false when plan does not support flexible licensing', async ({
|
|
UserMembershipController,
|
|
req,
|
|
PlansLocator,
|
|
}) => {
|
|
expect.assertions(1)
|
|
PlansLocator.findLocalPlanInSettings.mockReturnValue({
|
|
planCode: 'group_professional',
|
|
canUseFlexibleLicensing: false,
|
|
})
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should be false when user is not admin', async ({
|
|
UserMembershipController,
|
|
req,
|
|
SessionManager,
|
|
}) => {
|
|
expect.assertions(1)
|
|
SessionManager.getLoggedInUserId.mockReturnValue('mock-user-id')
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should be false when recurly subscription does not exist', async ({
|
|
UserMembershipController,
|
|
req,
|
|
subscription,
|
|
}) => {
|
|
expect.assertions(1)
|
|
subscription.recurlySubscription_id = null
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should be true when recurly subscription has pending changes', async ({
|
|
UserMembershipController,
|
|
req,
|
|
RecurlyClient,
|
|
}) => {
|
|
expect.assertions(1)
|
|
RecurlyClient.promises.getSubscription.mockResolvedValue({
|
|
id: recurlySubscriptionId,
|
|
pendingChange: {},
|
|
})
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(true)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should be false when fetching recurly subscription fails', async ({
|
|
UserMembershipController,
|
|
req,
|
|
RecurlyClient,
|
|
}) => {
|
|
expect.assertions(1)
|
|
RecurlyClient.promises.getSubscription.mockRejectedValue(
|
|
new Error('Recurly error')
|
|
)
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('should be false when plan is not found', async ({
|
|
UserMembershipController,
|
|
req,
|
|
PlansLocator,
|
|
}) => {
|
|
expect.assertions(1)
|
|
PlansLocator.findLocalPlanInSettings.mockReturnValue(null)
|
|
await UserMembershipController.manageGroupMembers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewParams.canUseAddSeatsFeature).to.equal(false)
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
it('render group managers view', async ({
|
|
UserMembershipController,
|
|
req,
|
|
user,
|
|
}) => {
|
|
expect.assertions(2)
|
|
req.user = user
|
|
req.entityConfig = EntityConfigs.groupManagers
|
|
await UserMembershipController.manageGroupManagers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewPath).to.equal('user_membership/group-managers-react')
|
|
expect(viewParams.groupSize).to.equal(undefined)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('render institution view', async ({
|
|
UserMembershipController,
|
|
req,
|
|
user,
|
|
institution,
|
|
}) => {
|
|
expect.assertions(3)
|
|
req.user = user
|
|
req.entity = institution
|
|
req.entityConfig = EntityConfigs.institution
|
|
await UserMembershipController.manageInstitutionManagers(req, {
|
|
render: (viewPath, viewParams) => {
|
|
expect(viewPath).to.equal(
|
|
'user_membership/institution-managers-react'
|
|
)
|
|
expect(viewParams.name).to.equal('Test Institution Name')
|
|
expect(viewParams.groupSize).to.equal(undefined)
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('add', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.body.email = ctx.newUser.email
|
|
ctx.req.entity = ctx.subscription
|
|
ctx.req.entityConfig = EntityConfigs.groupManagers
|
|
})
|
|
|
|
it('add user', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
subscription,
|
|
newUser,
|
|
}) => {
|
|
expect.assertions(1)
|
|
await UserMembershipController.add(req, {
|
|
json: () => {
|
|
expect(UserMembershipHandler.promises.addUser).toHaveBeenCalledWith(
|
|
subscription,
|
|
{
|
|
modelName: 'Subscription',
|
|
baseQuery: { groupPlan: true },
|
|
fields: {
|
|
access: 'manager_ids',
|
|
membership: 'member_ids',
|
|
name: 'teamName',
|
|
primaryKey: '_id',
|
|
read: ['manager_ids'],
|
|
write: 'manager_ids',
|
|
},
|
|
},
|
|
newUser.email
|
|
)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('return user object', async ({
|
|
UserMembershipController,
|
|
req,
|
|
newUser,
|
|
}) => {
|
|
expect.assertions(1)
|
|
await UserMembershipController.add(req, {
|
|
json: payload => {
|
|
expect(payload.user).to.equal(newUser)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('handle readOnly entity', async ({ UserMembershipController, req }) => {
|
|
expect.assertions(2)
|
|
req.entityConfig = EntityConfigs.group
|
|
await UserMembershipController.add(req, null, error => {
|
|
expect(error).to.exist
|
|
expect(error).to.be.an.instanceof(Errors.NotFoundError)
|
|
})
|
|
})
|
|
|
|
it('handle user already added', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
}) => {
|
|
expect.assertions(1)
|
|
UserMembershipHandler.promises.addUser.mockRejectedValue(
|
|
new UserMembershipErrors.UserAlreadyAddedError()
|
|
)
|
|
await UserMembershipController.add(
|
|
req,
|
|
{
|
|
status: () => ({
|
|
json: payload => {
|
|
expect(payload.error.code).to.equal('user_already_added')
|
|
},
|
|
}),
|
|
},
|
|
|
|
() => {}
|
|
)
|
|
})
|
|
|
|
it('handle user not found', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
}) => {
|
|
expect.assertions(1)
|
|
UserMembershipHandler.promises.addUser.mockRejectedValue(
|
|
new UserMembershipErrors.UserNotFoundError()
|
|
)
|
|
await UserMembershipController.add(req, {
|
|
status: () => ({
|
|
json: payload => {
|
|
expect(payload.error.code).to.equal('user_not_found')
|
|
},
|
|
}),
|
|
})
|
|
})
|
|
|
|
it('handle invalid email', async ({ UserMembershipController, req }) => {
|
|
expect.assertions(1)
|
|
req.body.email = 'not_valid_email'
|
|
await UserMembershipController.add(req, {
|
|
status: () => ({
|
|
json: payload => {
|
|
expect(payload.error.code).to.equal('invalid_email')
|
|
},
|
|
}),
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('remove', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.params.userId = ctx.newUser._id
|
|
ctx.req.entity = ctx.subscription
|
|
ctx.req.entityConfig = EntityConfigs.groupManagers
|
|
})
|
|
|
|
it('remove user', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
subscription,
|
|
newUser,
|
|
}) => {
|
|
expect.assertions(1)
|
|
await UserMembershipController.remove(req, {
|
|
sendStatus: () => {
|
|
expect(
|
|
UserMembershipHandler.promises.removeUser
|
|
).toHaveBeenCalledWith(
|
|
subscription,
|
|
{
|
|
modelName: 'Subscription',
|
|
|
|
baseQuery: {
|
|
groupPlan: true,
|
|
},
|
|
fields: {
|
|
access: 'manager_ids',
|
|
membership: 'member_ids',
|
|
name: 'teamName',
|
|
primaryKey: '_id',
|
|
read: ['manager_ids'],
|
|
write: 'manager_ids',
|
|
},
|
|
},
|
|
newUser._id
|
|
)
|
|
},
|
|
})
|
|
})
|
|
|
|
it('handle readOnly entity', async ({ UserMembershipController, req }) => {
|
|
expect.assertions(2)
|
|
req.entityConfig = EntityConfigs.group
|
|
await UserMembershipController.remove(req, null, error => {
|
|
expect(error).to.exist
|
|
expect(error).to.be.an.instanceof(Errors.NotFoundError)
|
|
})
|
|
})
|
|
|
|
it('prevent self removal', async ({
|
|
UserMembershipController,
|
|
req,
|
|
user,
|
|
}) => {
|
|
expect.assertions(1)
|
|
req.params.userId = user._id
|
|
await UserMembershipController.remove(req, {
|
|
status: () => ({
|
|
json: payload => {
|
|
expect(payload.error.code).to.equal('managers_cannot_remove_self')
|
|
},
|
|
}),
|
|
})
|
|
})
|
|
|
|
it('prevent admin removal', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
}) => {
|
|
expect.assertions(1)
|
|
UserMembershipHandler.promises.removeUser.mockRejectedValue(
|
|
new UserMembershipErrors.UserIsManagerError()
|
|
)
|
|
await UserMembershipController.remove(req, {
|
|
status: () => ({
|
|
json: payload => {
|
|
expect(payload.error.code).to.equal('managers_cannot_remove_admin')
|
|
},
|
|
}),
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('exportCsv', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.entity = ctx.subscription
|
|
ctx.req.entityConfig = EntityConfigs.groupManagers
|
|
ctx.res = new MockResponse(vi)
|
|
ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
|
|
})
|
|
|
|
it('get users', ({ UserMembershipHandler, subscription }) => {
|
|
expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
|
|
subscription,
|
|
{
|
|
modelName: 'Subscription',
|
|
baseQuery: { groupPlan: true },
|
|
fields: {
|
|
access: 'manager_ids',
|
|
membership: 'member_ids',
|
|
name: 'teamName',
|
|
primaryKey: '_id',
|
|
read: ['manager_ids'],
|
|
write: 'manager_ids',
|
|
},
|
|
}
|
|
)
|
|
})
|
|
|
|
it('should set the correct content type on the request', ({ res }) => {
|
|
expect(res.contentType).toHaveBeenCalledWith('text/csv; charset=utf-8')
|
|
})
|
|
|
|
it('should name the exported csv file', ({ res }) => {
|
|
expect(res.header).toHaveBeenCalledWith(
|
|
'Content-Disposition',
|
|
'attachment; filename="Group.csv"'
|
|
)
|
|
})
|
|
|
|
it('should export the correct csv', ({ res }) => {
|
|
expect(res.send).toHaveBeenCalledWith(
|
|
'"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"'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('exportCsv when group is managed', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.entity = Object.assign(
|
|
{ managedUsersEnabled: true },
|
|
ctx.subscription
|
|
)
|
|
ctx.req.entityConfig = EntityConfigs.groupManagers
|
|
ctx.res = new MockResponse(vi)
|
|
ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
|
|
})
|
|
|
|
it('should export the correct csv', ({ res }) => {
|
|
expect(res.send).toHaveBeenCalledWith(
|
|
'"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'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('exportCsv when group has SSO', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.entity = Object.assign(
|
|
{ ssoConfig: 'sso-config-id' },
|
|
ctx.subscription
|
|
)
|
|
ctx.req.entityConfig = EntityConfigs.groupManagers
|
|
ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
|
|
ctx.res = new MockResponse(vi)
|
|
ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
|
|
})
|
|
|
|
it('should export the correct csv', ({ res }) => {
|
|
expect(res.send).toHaveBeenCalledWith(
|
|
'"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'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('exportCsv when group has SSO and managed users enabled', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.entity = Object.assign(
|
|
{ managedUsersEnabled: true },
|
|
{ ssoConfig: 'sso-config-id' },
|
|
ctx.subscription
|
|
)
|
|
ctx.req.entityConfig = EntityConfigs.groupManagers
|
|
ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
|
|
ctx.res = new MockResponse(vi)
|
|
ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
|
|
})
|
|
|
|
it('should export the correct csv', ({ res }) => {
|
|
expect(res.send).toHaveBeenCalledWith(
|
|
'"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'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('new', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.params.name = 'publisher'
|
|
ctx.req.params.id = 'abc'
|
|
})
|
|
|
|
it('renders view', async ({ UserMembershipController, req }) => {
|
|
expect.assertions(2)
|
|
await UserMembershipController.new(req, {
|
|
render: (viewPath, data) => {
|
|
expect(data.entityName).to.eq('publisher')
|
|
expect(data.entityId).to.eq('abc')
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('create', () => {
|
|
beforeEach(ctx => {
|
|
ctx.req.params.name = 'institution'
|
|
ctx.req.entityConfig = EntityConfigs.institution
|
|
ctx.req.params.id = 123
|
|
})
|
|
|
|
it('creates institution', async ({
|
|
UserMembershipController,
|
|
req,
|
|
UserMembershipHandler,
|
|
}) => {
|
|
expect.assertions(2)
|
|
await UserMembershipController.create(req, {
|
|
redirect: path => {
|
|
expect(path).to.eq(EntityConfigs.institution.pathsFor(123).index)
|
|
expect(
|
|
UserMembershipHandler.promises.createEntity
|
|
).toHaveBeenCalledWith(123, {
|
|
fields: {
|
|
access: 'managerIds',
|
|
membership: 'member_ids',
|
|
name: 'name',
|
|
primaryKey: 'v1Id',
|
|
read: ['managerIds'],
|
|
write: 'managerIds',
|
|
},
|
|
modelName: 'Institution',
|
|
pathsFor: EntityConfigs.institution.pathsFor,
|
|
})
|
|
},
|
|
})
|
|
})
|
|
})
|
|
})
|