Files
overleaf-cep/services/web/test/unit/src/Subscription/TeamInvitesController.test.mjs
Andrew Rumble 23f76f9745 Convert return new Promise to await new Promise
GitOrigin-RevId: 49404748cc90cb7bdef0460f7e9837196f81cae8
2025-06-25 08:06:59 +00:00

278 lines
7.3 KiB
JavaScript

import { expect, vi } from 'vitest'
import sinon from 'sinon'
const modulePath =
'../../../../app/src/Features/Subscription/TeamInvitesController'
describe('TeamInvitesController', function () {
beforeEach(async function (ctx) {
ctx.user = { _id: '!@312431', email: 'user@email.com' }
ctx.adminUserId = '123jlkj'
ctx.subscriptionId = '123434325412'
ctx.user_email = 'bob@gmail.com'
ctx.req = {
session: {
user: {
_id: ctx.adminUserId,
email: ctx.user_email,
},
},
params: {},
query: {},
ip: '0.0.0.0',
}
ctx.subscription = {
_id: ctx.subscriptionId,
}
ctx.TeamInvitesHandler = {
promises: {
acceptInvite: sinon.stub().resolves(ctx.subscription),
getInvite: sinon.stub().resolves({
invite: {
email: ctx.user.email,
token: 'token123',
inviterName: ctx.user_email,
},
subscription: ctx.subscription,
}),
},
}
ctx.SubscriptionLocator = {
promises: {
hasSSOEnabled: sinon.stub().resolves(true),
getUsersSubscription: sinon.stub().resolves(),
},
}
ctx.ErrorController = { notFound: sinon.stub() }
ctx.SessionManager = {
getLoggedInUserId(session) {
return session.user?._id
},
getSessionUser(session) {
return session.user
},
}
ctx.UserAuditLogHandler = {
promises: {
addEntry: sinon.stub().resolves(),
},
}
ctx.UserGetter = {
promises: {
getUser: sinon.stub().resolves(ctx.user),
getUserByMainEmail: sinon.stub().resolves(ctx.user),
getUserByAnyEmail: sinon.stub().resolves(ctx.user),
},
}
ctx.EmailHandler = {
sendDeferredEmail: sinon.stub().resolves(),
}
ctx.RateLimiter = {
RateLimiter: class {},
}
vi.doMock(
'../../../../app/src/Features/Subscription/TeamInvitesHandler',
() => ({
default: ctx.TeamInvitesHandler,
})
)
vi.doMock(
'../../../../app/src/Features/Authentication/SessionManager',
() => ({
default: ctx.SessionManager,
})
)
vi.doMock(
'../../../../app/src/Features/Subscription/SubscriptionLocator',
() => ({
default: ctx.SubscriptionLocator,
})
)
vi.doMock('../../../../app/src/Features/User/UserAuditLogHandler', () => ({
default: ctx.UserAuditLogHandler,
}))
vi.doMock('../../../../app/src/Features/Errors/ErrorController', () => ({
default: ctx.ErrorController,
}))
vi.doMock('../../../../app/src/Features/User/UserGetter', () => ({
default: ctx.UserGetter,
}))
vi.doMock('../../../../app/src/Features/Email/EmailHandler', () => ({
default: ctx.EmailHandler,
}))
vi.doMock(
'../../../../app/src/infrastructure/RateLimiter',
() => ctx.RateLimiter
)
vi.doMock('../../../../app/src/infrastructure/Modules', () => ({
default: (ctx.Modules = {
promises: {
hooks: {
fire: sinon.stub().resolves([]),
},
},
}),
}))
vi.doMock(
'../../../../app/src/Features/SplitTests/SplitTestHandler',
() => ({
default: (ctx.SplitTestHandler = {
promises: {
getAssignment: sinon.stub().resolves({}),
},
}),
})
)
ctx.Controller = (await import(modulePath)).default
})
describe('acceptInvite', function () {
it('should add an audit log entry', async function (ctx) {
await new Promise(resolve => {
ctx.req.params.token = 'foo'
ctx.req.session.user = ctx.user
const res = {
json: () => {
sinon.assert.calledWith(
ctx.UserAuditLogHandler.promises.addEntry,
ctx.user._id,
'accept-group-invitation',
ctx.user._id,
ctx.req.ip,
{ subscriptionId: ctx.subscriptionId }
)
resolve()
},
}
ctx.Controller.acceptInvite(ctx.req, res)
})
})
})
describe('viewInvite', function () {
const req = {
params: { token: 'token123' },
query: {},
session: {
user: { _id: 'user123' },
},
}
describe('hasIndividualPaidSubscription', function () {
it('is true for personal subscription', async function (ctx) {
await new Promise(resolve => {
ctx.SubscriptionLocator.promises.getUsersSubscription.resolves({
recurlySubscription_id: 'subscription123',
groupPlan: false,
})
const res = {
render: (template, data) => {
expect(data.hasIndividualPaidSubscription).to.be.true
resolve()
},
}
ctx.Controller.viewInvite(req, res)
})
})
it('is true for group subscriptions', async function (ctx) {
await new Promise(resolve => {
ctx.SubscriptionLocator.promises.getUsersSubscription.resolves({
recurlySubscription_id: 'subscription123',
groupPlan: true,
})
const res = {
render: (template, data) => {
expect(data.hasIndividualPaidSubscription).to.be.false
resolve()
},
}
ctx.Controller.viewInvite(req, res)
})
})
it('is false for canceled subscriptions', async function (ctx) {
await new Promise(resolve => {
ctx.SubscriptionLocator.promises.getUsersSubscription.resolves({
recurlySubscription_id: 'subscription123',
groupPlan: false,
recurlyStatus: {
state: 'canceled',
},
})
const res = {
render: (template, data) => {
expect(data.hasIndividualPaidSubscription).to.be.false
resolve()
},
}
ctx.Controller.viewInvite(req, res)
})
})
})
describe('when user is logged out', function () {
it('renders logged out invite page', async function (ctx) {
await new Promise(resolve => {
const res = {
render: (template, data) => {
expect(template).to.equal('subscriptions/team/invite_logged_out')
expect(data.groupSSOActive).to.be.undefined
resolve()
},
}
ctx.Controller.viewInvite(
{ params: { token: 'token123' }, session: {} },
res
)
})
})
it('includes groupSSOActive flag when the group has SSO enabled', async function (ctx) {
await new Promise(resolve => {
ctx.Modules.promises.hooks.fire = sinon.stub().resolves([true])
const res = {
render: (template, data) => {
expect(data.groupSSOActive).to.be.true
resolve()
},
}
ctx.Controller.viewInvite(
{ params: { token: 'token123' }, session: {} },
res
)
})
})
})
it('renders the view', async function (ctx) {
await new Promise(resolve => {
const res = {
render: template => {
expect(template).to.equal('subscriptions/team/invite')
resolve()
},
}
ctx.Controller.viewInvite(req, res)
})
})
})
})