Merge pull request #36194 from overleaf/rh-cio-split-tests

[web] send active split test assignments to customer.io

GitOrigin-RevId: 3036d6442e8419326f4b641482d65bd5114fe3da
This commit is contained in:
roo hutton
2026-09-17 11:49:59 +00:00
committed by Copybot
parent df7a9159c2
commit 6b69ea7dc1
3 changed files with 64 additions and 1 deletions
@@ -578,6 +578,21 @@ async function projectListPage(req, res, next) {
}
}
let splitTestUserProperties
if (isSaas) {
try {
;[splitTestUserProperties] = await Modules.promises.hooks.fire(
'getSplitTestUserProperties',
userId
)
} catch (err) {
logger.error(
{ err, userId },
'Failed to build split test user properties for customer.io'
)
}
}
Modules.promises.hooks
.fire('setUserProperties', userId, {
overleaf_id: userId,
@@ -602,6 +617,7 @@ async function projectListPage(req, res, next) {
...(groupRole && { group_role: groupRole }),
is_managed_user: Boolean(user.enrollment?.managedBy),
...(user.email && { email: user.email }),
...splitTestUserProperties,
})
.catch(err => {
logger.error({ err }, 'Failed to set user properties for customer.io')
@@ -45,7 +45,7 @@ function getProjection(splitTestName) {
/**
* @param id
* @param {string} splitTestName
* @param {string} [splitTestName] test to get; omit to fetch all assignments.
* @param {string} path
* @return {Promise<SplitTestUser>}
*/
@@ -568,6 +568,53 @@ describe('ProjectListController', function () {
)
})
it('should send packed split test assignments to customer.io', async function (ctx) {
ctx.Features.hasFeature.withArgs('saas').returns(true)
ctx.Modules.promises.hooks.fire
.withArgs('getSplitTestUserProperties', ctx.user._id)
.resolves([{ split_test_assignments: { 'test-a': 'variant-1' } }])
ctx.res.render = () => {}
await ctx.ProjectListController.projectListPage(ctx.req, ctx.res)
expect(ctx.Modules.promises.hooks.fire).to.have.been.calledWith(
'setUserProperties',
ctx.user._id,
sinon.match({
split_test_assignments: { 'test-a': 'variant-1' },
})
)
})
it('should not request split test user properties in a non-saas environment', async function (ctx) {
ctx.Features.hasFeature.withArgs('saas').returns(false)
ctx.res.render = () => {}
await ctx.ProjectListController.projectListPage(ctx.req, ctx.res)
expect(ctx.Modules.promises.hooks.fire).to.not.have.been.calledWith(
'getSplitTestUserProperties',
sinon.match.any
)
})
it('should still send other user properties when building split test assignments fails', async function (ctx) {
ctx.Features.hasFeature.withArgs('saas').returns(true)
ctx.Modules.promises.hooks.fire
.withArgs('getSplitTestUserProperties', ctx.user._id)
.rejects(new Error('boom'))
ctx.res.render = () => {}
await ctx.ProjectListController.projectListPage(ctx.req, ctx.res)
const call = ctx.Modules.promises.hooks.fire
.getCalls()
.find(call => call.args[0] === 'setUserProperties')
expect(call).to.exist
expect(call.args[2]).to.not.have.property('split_test_assignments')
expect(call.args[2]).to.have.property('overleaf_id', ctx.user._id)
})
it('should send enterprise_commons=true when user has commons from an enterprise_commons institution', async function (ctx) {
ctx.Features.hasFeature.withArgs('saas').returns(true)
ctx.UserGetter.promises.getUserFullEmails.resolves([