mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
[web] Convert some Features files to ES modules (part 2) (#28275)
* Rename files * Rename test files * Convert to ESM GitOrigin-RevId: b0ee442ac8edd4ef3695f93a91ffd9521e6bf259
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
import OError from '@overleaf/o-error'
|
||||
import ProjectGetter from '../Project/ProjectGetter.js'
|
||||
import ProjectHistoryHandler from '../Project/ProjectHistoryHandler.js'
|
||||
import ProjectHistoryHandler from '../Project/ProjectHistoryHandler.mjs'
|
||||
import ProjectLocator from '../Project/ProjectLocator.js'
|
||||
import ProjectRootDocManager from '../Project/ProjectRootDocManager.js'
|
||||
import UserGetter from '../User/UserGetter.js'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { callbackify } = require('util')
|
||||
const Path = require('path')
|
||||
const ProjectEntityHandler = require('./ProjectEntityHandler')
|
||||
const EditorController = require('../Editor/EditorController')
|
||||
import { callbackify } from 'node:util'
|
||||
import Path from 'node:path'
|
||||
import ProjectEntityHandler from './ProjectEntityHandler.js'
|
||||
import EditorController from '../Editor/EditorController.js'
|
||||
|
||||
// generate a new name based on the original, with an optional label.
|
||||
// e.g. origname-20210101-122345.tex (default)
|
||||
@@ -36,7 +36,7 @@ async function restoreDeletedDoc(projectId, docId, docName, userId) {
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
restoreDeletedDoc: callbackify(restoreDeletedDoc),
|
||||
generateRestoredName,
|
||||
promises: {
|
||||
@@ -1,8 +1,8 @@
|
||||
const { Project } = require('../../models/Project')
|
||||
const ProjectDetailsHandler = require('./ProjectDetailsHandler')
|
||||
const HistoryManager = require('../History/HistoryManager')
|
||||
const ProjectEntityUpdateHandler = require('./ProjectEntityUpdateHandler')
|
||||
const { callbackify } = require('util')
|
||||
import { Project } from '../../models/Project.js'
|
||||
import ProjectDetailsHandler from './ProjectDetailsHandler.js'
|
||||
import HistoryManager from '../History/HistoryManager.js'
|
||||
import ProjectEntityUpdateHandler from './ProjectEntityUpdateHandler.js'
|
||||
import { callbackify } from 'node:util'
|
||||
|
||||
const ProjectHistoryHandler = {
|
||||
async setHistoryId(projectId, historyId) {
|
||||
@@ -55,7 +55,7 @@ const ProjectHistoryHandler = {
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
setHistoryId: callbackify(ProjectHistoryHandler.setHistoryId),
|
||||
getHistoryId: callbackify(ProjectHistoryHandler.getHistoryId),
|
||||
ensureHistoryExistsForProject: callbackify(
|
||||
@@ -1,7 +1,7 @@
|
||||
const OError = require('@overleaf/o-error')
|
||||
const { User } = require('../../models/User')
|
||||
const FeaturesUpdater = require('../Subscription/FeaturesUpdater')
|
||||
const { callbackify } = require('@overleaf/promise-utils')
|
||||
import OError from '@overleaf/o-error'
|
||||
import { User } from '../../models/User.js'
|
||||
import FeaturesUpdater from '../Subscription/FeaturesUpdater.js'
|
||||
import { callbackify } from '@overleaf/promise-utils'
|
||||
|
||||
async function allocate(referalId, newUserId, referalSource, referalMedium) {
|
||||
if (referalId == null) {
|
||||
@@ -40,7 +40,7 @@ async function allocate(referalId, newUserId, referalSource, referalMedium) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
allocate: callbackify(allocate),
|
||||
promises: {
|
||||
allocate,
|
||||
@@ -1,11 +1,11 @@
|
||||
const logger = require('@overleaf/logger')
|
||||
const http = require('http')
|
||||
const https = require('https')
|
||||
const Settings = require('@overleaf/settings')
|
||||
const TpdsUpdateSender = require('../ThirdPartyDataStore/TpdsUpdateSender')
|
||||
const TpdsProjectFlusher = require('../ThirdPartyDataStore/TpdsProjectFlusher')
|
||||
const EditorRealTimeController = require('../Editor/EditorRealTimeController')
|
||||
const SystemMessageManager = require('../SystemMessages/SystemMessageManager')
|
||||
import logger from '@overleaf/logger'
|
||||
import http from 'node:http'
|
||||
import https from 'node:https'
|
||||
import Settings from '@overleaf/settings'
|
||||
import TpdsUpdateSender from '../ThirdPartyDataStore/TpdsUpdateSender.js'
|
||||
import TpdsProjectFlusher from '../ThirdPartyDataStore/TpdsProjectFlusher.js'
|
||||
import EditorRealTimeController from '../Editor/EditorRealTimeController.js'
|
||||
import SystemMessageManager from '../SystemMessages/SystemMessageManager.js'
|
||||
|
||||
const AdminController = {
|
||||
_sendDisconnectAllUsersMessage: delay => {
|
||||
@@ -94,4 +94,4 @@ const AdminController = {
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = AdminController
|
||||
export default AdminController
|
||||
@@ -1,8 +1,8 @@
|
||||
const logger = require('@overleaf/logger')
|
||||
const Settings = require('@overleaf/settings')
|
||||
const { IncomingWebhook } = require('@slack/webhook')
|
||||
const moment = require('moment')
|
||||
const SplitTestUtils = require('./SplitTestUtils')
|
||||
import logger from '@overleaf/logger'
|
||||
import Settings from '@overleaf/settings'
|
||||
import { IncomingWebhook } from '@slack/webhook'
|
||||
import moment from 'moment'
|
||||
import SplitTestUtils from './SplitTestUtils.js'
|
||||
|
||||
async function sendNotification(splitTest, action, user) {
|
||||
const lastVersion = SplitTestUtils.getCurrentVersion(splitTest)
|
||||
@@ -60,6 +60,6 @@ async function sendNotification(splitTest, action, user) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
sendNotification,
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
const SplitTestHandler = require('./SplitTestHandler')
|
||||
const logger = require('@overleaf/logger')
|
||||
const { expressify } = require('@overleaf/promise-utils')
|
||||
const Errors = require('../Errors/Errors')
|
||||
import SplitTestHandler from './SplitTestHandler.js'
|
||||
import logger from '@overleaf/logger'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
import Errors from '../Errors/Errors.js'
|
||||
|
||||
function loadAssignmentsInLocals(splitTestNames) {
|
||||
return async function (req, res, next) {
|
||||
@@ -43,7 +43,7 @@ function ensureSplitTestEnabledForUser(
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
loadAssignmentsInLocals,
|
||||
ensureSplitTestEnabledForUser,
|
||||
}
|
||||
@@ -9,6 +9,6 @@ function getProviderId(subscriptionId) {
|
||||
return `ol-group-subscription-id:${subscriptionId.toString()}`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
getProviderId,
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import SubscriptionGroupHandler from './SubscriptionGroupHandler.js'
|
||||
import SubscriptionGroupHandler from './SubscriptionGroupHandler.mjs'
|
||||
|
||||
import OError from '@overleaf/o-error'
|
||||
import logger from '@overleaf/logger'
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
const { callbackify } = require('util')
|
||||
const _ = require('lodash')
|
||||
const OError = require('@overleaf/o-error')
|
||||
const SubscriptionUpdater = require('./SubscriptionUpdater')
|
||||
const SubscriptionLocator = require('./SubscriptionLocator')
|
||||
const SubscriptionController = require('./SubscriptionController')
|
||||
const SubscriptionHelper = require('./SubscriptionHelper')
|
||||
const { Subscription } = require('../../models/Subscription')
|
||||
const { User } = require('../../models/User')
|
||||
const PlansLocator = require('./PlansLocator')
|
||||
const TeamInvitesHandler = require('./TeamInvitesHandler')
|
||||
const GroupPlansData = require('./GroupPlansData')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
const { MEMBERS_LIMIT_ADD_ON_CODE } = require('./PaymentProviderEntities')
|
||||
const {
|
||||
import { callbackify } from 'node:util'
|
||||
import _ from 'lodash'
|
||||
import OError from '@overleaf/o-error'
|
||||
import SubscriptionUpdater from './SubscriptionUpdater.js'
|
||||
import SubscriptionLocator from './SubscriptionLocator.js'
|
||||
import SubscriptionController from './SubscriptionController.js'
|
||||
import SubscriptionHelper from './SubscriptionHelper.js'
|
||||
import { Subscription } from '../../models/Subscription.js'
|
||||
import { User } from '../../models/User.js'
|
||||
import PlansLocator from './PlansLocator.js'
|
||||
import TeamInvitesHandler from './TeamInvitesHandler.js'
|
||||
import GroupPlansData from './GroupPlansData.js'
|
||||
import Modules from '../../infrastructure/Modules.js'
|
||||
import PaymentProviderEntities from './PaymentProviderEntities.js'
|
||||
import {
|
||||
ManuallyCollectedError,
|
||||
PendingChangeError,
|
||||
InactiveError,
|
||||
HasPastDueInvoiceError,
|
||||
HasNoAdditionalLicenseWhenManuallyCollectedError,
|
||||
} = require('./Errors')
|
||||
const EmailHelper = require('../Helpers/EmailHelper')
|
||||
const { InvalidEmailError } = require('../Errors/Errors')
|
||||
} from './Errors.js'
|
||||
import EmailHelper from '../Helpers/EmailHelper.js'
|
||||
import { InvalidEmailError } from '../Errors/Errors.js'
|
||||
|
||||
const MEMBERS_LIMIT_ADD_ON_CODE =
|
||||
PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE
|
||||
|
||||
async function removeUserFromGroup(subscriptionId, userIdToRemove, auditLog) {
|
||||
await SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
@@ -470,7 +473,7 @@ async function updateGroupMembersBulk(
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
removeUserFromGroup: callbackify(removeUserFromGroup),
|
||||
replaceUserReferencesInGroups: callbackify(replaceUserReferencesInGroups),
|
||||
ensureFlexibleLicensingEnabled: callbackify(ensureFlexibleLicensingEnabled),
|
||||
@@ -1,4 +1,4 @@
|
||||
import SurveyManager from './SurveyManager.js'
|
||||
import SurveyManager from './SurveyManager.mjs'
|
||||
import { Survey } from '../../models/Survey.js'
|
||||
import { CacheLoader } from 'cache-flow'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { Survey } = require('../../models/Survey')
|
||||
const OError = require('@overleaf/o-error')
|
||||
import { Survey } from '../../models/Survey.js'
|
||||
import OError from '@overleaf/o-error'
|
||||
|
||||
async function getSurvey() {
|
||||
try {
|
||||
@@ -67,7 +67,7 @@ async function deleteSurvey() {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
getSurvey,
|
||||
updateSurvey,
|
||||
deleteSurvey,
|
||||
@@ -1,6 +1,6 @@
|
||||
const Settings = require('@overleaf/settings')
|
||||
const SessionManager = require('../Authentication/SessionManager')
|
||||
const SystemMessageManager = require('./SystemMessageManager')
|
||||
import Settings from '@overleaf/settings'
|
||||
import SessionManager from '../Authentication/SessionManager.js'
|
||||
import SystemMessageManager from './SystemMessageManager.js'
|
||||
|
||||
const ProjectController = {
|
||||
getMessages(req, res, next) {
|
||||
@@ -24,4 +24,4 @@ const ProjectController = {
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = ProjectController
|
||||
export default ProjectController
|
||||
@@ -1,4 +1,4 @@
|
||||
import AdminController from './Features/ServerAdmin/AdminController.js'
|
||||
import AdminController from './Features/ServerAdmin/AdminController.mjs'
|
||||
import ErrorController from './Features/Errors/ErrorController.mjs'
|
||||
import Features from './infrastructure/Features.js'
|
||||
import ProjectController from './Features/Project/ProjectController.mjs'
|
||||
@@ -54,7 +54,7 @@ import TokenAccessRouter from './Features/TokenAccess/TokenAccessRouter.mjs'
|
||||
import LinkedFilesRouter from './Features/LinkedFiles/LinkedFilesRouter.mjs'
|
||||
import TemplatesRouter from './Features/Templates/TemplatesRouter.js'
|
||||
import UserMembershipRouter from './Features/UserMembership/UserMembershipRouter.mjs'
|
||||
import SystemMessageController from './Features/SystemMessages/SystemMessageController.js'
|
||||
import SystemMessageController from './Features/SystemMessages/SystemMessageController.mjs'
|
||||
import AnalyticsRegistrationSourceMiddleware from './Features/Analytics/AnalyticsRegistrationSourceMiddleware.js'
|
||||
import AnalyticsUTMTrackingMiddleware from './Features/Analytics/AnalyticsUTMTrackingMiddleware.mjs'
|
||||
import CaptchaMiddleware from './Features/Captcha/CaptchaMiddleware.mjs'
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from 'node:fs'
|
||||
import minimist from 'minimist'
|
||||
import { parse } from 'csv'
|
||||
import Stream from 'node:stream/promises'
|
||||
import SubscriptionGroupHandler from '../app/src/Features/Subscription/SubscriptionGroupHandler.js'
|
||||
import SubscriptionGroupHandler from '../app/src/Features/Subscription/SubscriptionGroupHandler.mjs'
|
||||
import { Subscription } from '../app/src/models/Subscription.js'
|
||||
import { InvalidEmailError } from '../app/src/Features/Errors/Errors.js'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { promisify } from 'node:util'
|
||||
import Settings from '@overleaf/settings'
|
||||
import AdminController from '../app/src/Features/ServerAdmin/AdminController.js'
|
||||
import AdminController from '../app/src/Features/ServerAdmin/AdminController.mjs'
|
||||
import minimist from 'minimist'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { scriptRunner } from './lib/ScriptRunner.mjs'
|
||||
|
||||
@@ -4,7 +4,7 @@ import minimist from 'minimist'
|
||||
|
||||
import { db, ObjectId } from '../app/src/infrastructure/mongodb.js'
|
||||
import ProjectEntityUpdateHandler from '../app/src/Features/Project/ProjectEntityUpdateHandler.js'
|
||||
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.js'
|
||||
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.mjs'
|
||||
import RedisWrapper from '@overleaf/redis-wrapper'
|
||||
import Settings from '@overleaf/settings'
|
||||
import logger from '@overleaf/logger'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.js'
|
||||
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.mjs'
|
||||
import ProjectEntityHandler from '../app/src/Features/Project/ProjectEntityHandler.js'
|
||||
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
|
||||
import { scriptRunner } from './lib/ScriptRunner.mjs'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.js'
|
||||
import ProjectEntityRestoreHandler from '../app/src/Features/Project/ProjectEntityRestoreHandler.mjs'
|
||||
import DocstoreManager from '../app/src/Features/Docstore/DocstoreManager.js'
|
||||
import { scriptRunner } from './lib/ScriptRunner.mjs'
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { SSOConfig } from '../../../../app/src/models/SSOConfig.js'
|
||||
import UserHelper from './UserHelper.mjs'
|
||||
import SAMLHelper from './SAMLHelper.mjs'
|
||||
import Settings from '@overleaf/settings'
|
||||
import { getProviderId } from '../../../../app/src/Features/Subscription/GroupUtils.js'
|
||||
import GroupUtils from '../../../../app/src/Features/Subscription/GroupUtils.mjs'
|
||||
import UserGetter from '../../../../app/src/Features/User/UserGetter.js'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { Subscription as SubscriptionModel } from '../../../../app/src/models/Subscription.js'
|
||||
@@ -75,7 +75,7 @@ export async function createGroupSSO(
|
||||
await subscription.ensureExists()
|
||||
const subscriptionId = subscription._id.toString()
|
||||
const enrollmentUrl = getEnrollmentUrl(subscriptionId)
|
||||
const internalProviderId = getProviderId(subscriptionId)
|
||||
const internalProviderId = GroupUtils.getProviderId(subscriptionId)
|
||||
|
||||
if (SSOConfigValidated) {
|
||||
await linkGroupMember(
|
||||
@@ -122,7 +122,7 @@ export async function linkGroupMember(
|
||||
.exec()
|
||||
const userIdAttribute = subscription?.ssoConfig?.userIdAttribute
|
||||
|
||||
const internalProviderId = getProviderId(groupId)
|
||||
const internalProviderId = GroupUtils.getProviderId(groupId)
|
||||
const enrollmentUrl = getEnrollmentUrl(groupId)
|
||||
const userHelper = await UserHelper.loginUser(
|
||||
{
|
||||
@@ -189,7 +189,7 @@ export async function linkGroupMember(
|
||||
}
|
||||
|
||||
export async function checkUserHasSSOLinked(userId, groupId) {
|
||||
const internalProviderId = getProviderId(groupId)
|
||||
const internalProviderId = GroupUtils.getProviderId(groupId)
|
||||
const user = await UserGetter.promises.getUser(
|
||||
{ _id: userId },
|
||||
{ samlIdentifiers: 1, enrollment: 1 }
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import { vi, expect } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const MODULE_PATH =
|
||||
'../../../../app/src/Features/Project/ProjectEntityRestoreHandler.mjs'
|
||||
|
||||
describe('ProjectEntityRestoreHandler', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.project = {
|
||||
_id: '123213jlkj9kdlsaj',
|
||||
}
|
||||
|
||||
ctx.user = {
|
||||
_id: '588f3ddae8ebc1bac07c9fa4',
|
||||
first_name: 'bjkdsjfk',
|
||||
features: {},
|
||||
}
|
||||
|
||||
ctx.docId = '4eecb1c1bffa66588e0000a2'
|
||||
|
||||
ctx.DocModel = class Doc {
|
||||
constructor(options) {
|
||||
this.name = options.name
|
||||
this.lines = options.lines
|
||||
this._id = this.docId
|
||||
this.rev = 0
|
||||
}
|
||||
}
|
||||
|
||||
ctx.ProjectEntityHandler = {
|
||||
promises: {
|
||||
getDoc: sinon.stub(),
|
||||
},
|
||||
}
|
||||
|
||||
ctx.EditorController = {
|
||||
promises: {
|
||||
addDocWithRanges: sinon.stub(),
|
||||
},
|
||||
}
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Project/ProjectEntityHandler.js',
|
||||
() => ({
|
||||
default: ctx.ProjectEntityHandler,
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Editor/EditorController.js',
|
||||
() => ({
|
||||
default: ctx.EditorController,
|
||||
})
|
||||
)
|
||||
|
||||
ctx.ProjectEntityRestoreHandler = (await import(MODULE_PATH)).default
|
||||
})
|
||||
|
||||
it('should add a new doc with timestamp name and old content', async function (ctx) {
|
||||
const docName = 'deletedDoc'
|
||||
|
||||
ctx.docLines = ['line one', 'line two']
|
||||
ctx.rev = 3
|
||||
ctx.ranges = { comments: [{ id: 123 }] }
|
||||
|
||||
ctx.newDoc = new ctx.DocModel({
|
||||
name: ctx.docName,
|
||||
lines: undefined,
|
||||
_id: ctx.docId,
|
||||
rev: 0,
|
||||
})
|
||||
|
||||
ctx.ProjectEntityHandler.promises.getDoc.resolves({
|
||||
lines: ctx.docLines,
|
||||
rev: ctx.rev,
|
||||
version: 'version',
|
||||
ranges: ctx.ranges,
|
||||
})
|
||||
|
||||
ctx.EditorController.promises.addDocWithRanges = sinon
|
||||
.stub()
|
||||
.resolves(ctx.newDoc)
|
||||
|
||||
await ctx.ProjectEntityRestoreHandler.promises.restoreDeletedDoc(
|
||||
ctx.project._id,
|
||||
ctx.docId,
|
||||
docName,
|
||||
ctx.user._id
|
||||
)
|
||||
|
||||
const docNameMatcher = new RegExp(docName + '-\\d{4}-\\d{2}-\\d{2}-\\d+')
|
||||
|
||||
expect(
|
||||
ctx.EditorController.promises.addDocWithRanges
|
||||
).to.have.been.calledWith(
|
||||
ctx.project._id,
|
||||
null,
|
||||
sinon.match(docNameMatcher),
|
||||
ctx.docLines,
|
||||
ctx.ranges,
|
||||
null,
|
||||
ctx.user._id
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -1,97 +0,0 @@
|
||||
const { expect } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
|
||||
const MODULE_PATH =
|
||||
'../../../../app/src/Features/Project/ProjectEntityRestoreHandler.js'
|
||||
|
||||
describe('ProjectEntityRestoreHandler', function () {
|
||||
beforeEach(function () {
|
||||
this.project = {
|
||||
_id: '123213jlkj9kdlsaj',
|
||||
}
|
||||
|
||||
this.user = {
|
||||
_id: '588f3ddae8ebc1bac07c9fa4',
|
||||
first_name: 'bjkdsjfk',
|
||||
features: {},
|
||||
}
|
||||
|
||||
this.docId = '4eecb1c1bffa66588e0000a2'
|
||||
|
||||
this.DocModel = class Doc {
|
||||
constructor(options) {
|
||||
this.name = options.name
|
||||
this.lines = options.lines
|
||||
this._id = this.docId
|
||||
this.rev = 0
|
||||
}
|
||||
}
|
||||
|
||||
this.ProjectEntityHandler = {
|
||||
promises: {
|
||||
getDoc: sinon.stub(),
|
||||
},
|
||||
}
|
||||
|
||||
this.EditorController = {
|
||||
promises: {
|
||||
addDocWithRanges: sinon.stub(),
|
||||
},
|
||||
}
|
||||
|
||||
this.ProjectEntityRestoreHandler = SandboxedModule.require(MODULE_PATH, {
|
||||
requires: {
|
||||
'./ProjectEntityHandler': this.ProjectEntityHandler,
|
||||
'../Editor/EditorController': this.EditorController,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should add a new doc with timestamp name and old content', async function () {
|
||||
const docName = 'deletedDoc'
|
||||
|
||||
this.docLines = ['line one', 'line two']
|
||||
this.rev = 3
|
||||
this.ranges = { comments: [{ id: 123 }] }
|
||||
|
||||
this.newDoc = new this.DocModel({
|
||||
name: this.docName,
|
||||
lines: undefined,
|
||||
_id: this.docId,
|
||||
rev: 0,
|
||||
})
|
||||
|
||||
this.ProjectEntityHandler.promises.getDoc.resolves({
|
||||
lines: this.docLines,
|
||||
rev: this.rev,
|
||||
version: 'version',
|
||||
ranges: this.ranges,
|
||||
})
|
||||
|
||||
this.EditorController.promises.addDocWithRanges = sinon
|
||||
.stub()
|
||||
.resolves(this.newDoc)
|
||||
|
||||
await this.ProjectEntityRestoreHandler.promises.restoreDeletedDoc(
|
||||
this.project._id,
|
||||
this.docId,
|
||||
docName,
|
||||
this.user._id
|
||||
)
|
||||
|
||||
const docNameMatcher = new RegExp(docName + '-\\d{4}-\\d{2}-\\d{2}-\\d+')
|
||||
|
||||
expect(
|
||||
this.EditorController.promises.addDocWithRanges
|
||||
).to.have.been.calledWith(
|
||||
this.project._id,
|
||||
null,
|
||||
sinon.match(docNameMatcher),
|
||||
this.docLines,
|
||||
this.ranges,
|
||||
null,
|
||||
this.user._id
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,166 @@
|
||||
import { vi } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Project/ProjectHistoryHandler.mjs'
|
||||
|
||||
describe('ProjectHistoryHandler', function () {
|
||||
const projectId = '4eecb1c1bffa66588e0000a1'
|
||||
|
||||
beforeEach(async function (ctx) {
|
||||
let Project
|
||||
ctx.ProjectModel = Project = (function () {
|
||||
Project = class Project {
|
||||
static initClass() {
|
||||
this.prototype.rootFolder = [this.rootFolder]
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
this._id = projectId
|
||||
this.name = 'project_name_here'
|
||||
this.rev = 0
|
||||
}
|
||||
}
|
||||
Project.initClass()
|
||||
return Project
|
||||
})()
|
||||
ctx.project = new ctx.ProjectModel()
|
||||
ctx.historyId = ctx.project._id.toString()
|
||||
|
||||
ctx.callback = sinon.stub()
|
||||
|
||||
vi.doMock('@overleaf/settings', () => ({
|
||||
default: (ctx.Settings = {}),
|
||||
}))
|
||||
|
||||
vi.doMock('../../../../app/src/models/Project.js', () => ({
|
||||
Project: ctx.ProjectModel,
|
||||
}))
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Project/ProjectDetailsHandler.js',
|
||||
() => ({
|
||||
default: (ctx.ProjectDetailsHandler = {
|
||||
promises: {},
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock('../../../../app/src/Features/History/HistoryManager.js', () => ({
|
||||
default: (ctx.HistoryManager = {
|
||||
promises: {},
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Project/ProjectEntityUpdateHandler',
|
||||
() => ({
|
||||
default: (ctx.ProjectEntityUpdateHandler = {
|
||||
promises: {},
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
return (ctx.ProjectHistoryHandler = (await import(modulePath)).default)
|
||||
})
|
||||
|
||||
describe('starting history for an existing project', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.HistoryManager.promises.initializeProject = sinon
|
||||
.stub()
|
||||
.resolves(ctx.historyId)
|
||||
ctx.HistoryManager.promises.flushProject = sinon.stub()
|
||||
|
||||
return (ctx.ProjectEntityUpdateHandler.promises.resyncProjectHistory =
|
||||
sinon.stub())
|
||||
})
|
||||
|
||||
describe('when the history does not already exist', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.ProjectDetailsHandler.promises.getDetails = sinon
|
||||
.stub()
|
||||
.withArgs(projectId)
|
||||
.resolves(ctx.project)
|
||||
ctx.ProjectModel.updateOne = sinon.stub().resolves({ matchedCount: 1 })
|
||||
return ctx.ProjectHistoryHandler.promises.ensureHistoryExistsForProject(
|
||||
projectId
|
||||
)
|
||||
})
|
||||
|
||||
it('should get any existing history id for the project', async function (ctx) {
|
||||
return ctx.ProjectDetailsHandler.promises.getDetails
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should initialize a new history in the v1 history service', async function (ctx) {
|
||||
return ctx.HistoryManager.promises.initializeProject.called.should.equal(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('should set the new history id on the project', async function (ctx) {
|
||||
return ctx.ProjectModel.updateOne
|
||||
.calledWith(
|
||||
{ _id: projectId, 'overleaf.history.id': { $exists: false } },
|
||||
{ 'overleaf.history.id': ctx.historyId }
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should resync the project history', async function (ctx) {
|
||||
return ctx.ProjectEntityUpdateHandler.promises.resyncProjectHistory
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should flush the project history', async function (ctx) {
|
||||
return ctx.HistoryManager.promises.flushProject
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the history already exists', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.project.overleaf = { history: { id: 1234 } }
|
||||
ctx.ProjectDetailsHandler.promises.getDetails = sinon
|
||||
.stub()
|
||||
.withArgs(projectId)
|
||||
.resolves(ctx.project)
|
||||
ctx.ProjectModel.updateOne = sinon.stub().resolves({ matchedCount: 1 })
|
||||
return ctx.ProjectHistoryHandler.promises.ensureHistoryExistsForProject(
|
||||
projectId
|
||||
)
|
||||
})
|
||||
|
||||
it('should get any existing history id for the project', async function (ctx) {
|
||||
return ctx.ProjectDetailsHandler.promises.getDetails
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not initialize a new history in the v1 history service', async function (ctx) {
|
||||
return ctx.HistoryManager.promises.initializeProject.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('should not set the new history id on the project', async function (ctx) {
|
||||
return ctx.ProjectModel.updateOne.called.should.equal(false)
|
||||
})
|
||||
|
||||
it('should not resync the project history', async function (ctx) {
|
||||
return ctx.ProjectEntityUpdateHandler.promises.resyncProjectHistory.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('should not flush the project history', async function (ctx) {
|
||||
return ctx.HistoryManager.promises.flushProject.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,163 +0,0 @@
|
||||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS206: Consider reworking classes to avoid initClass
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const { assert, expect } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = '../../../../app/src/Features/Project/ProjectHistoryHandler'
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe('ProjectHistoryHandler', function () {
|
||||
const projectId = '4eecb1c1bffa66588e0000a1'
|
||||
const userId = 1234
|
||||
|
||||
beforeEach(function () {
|
||||
let Project
|
||||
this.ProjectModel = Project = (function () {
|
||||
Project = class Project {
|
||||
static initClass() {
|
||||
this.prototype.rootFolder = [this.rootFolder]
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
this._id = projectId
|
||||
this.name = 'project_name_here'
|
||||
this.rev = 0
|
||||
}
|
||||
}
|
||||
Project.initClass()
|
||||
return Project
|
||||
})()
|
||||
this.project = new this.ProjectModel()
|
||||
this.historyId = this.project._id.toString()
|
||||
|
||||
this.callback = sinon.stub()
|
||||
|
||||
return (this.ProjectHistoryHandler = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'@overleaf/settings': (this.Settings = {}),
|
||||
'../../models/Project': {
|
||||
Project: this.ProjectModel,
|
||||
},
|
||||
'./ProjectDetailsHandler': (this.ProjectDetailsHandler = {
|
||||
promises: {},
|
||||
}),
|
||||
'../History/HistoryManager': (this.HistoryManager = {
|
||||
promises: {},
|
||||
}),
|
||||
'./ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {
|
||||
promises: {},
|
||||
}),
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
describe('starting history for an existing project', function () {
|
||||
beforeEach(async function () {
|
||||
this.HistoryManager.promises.initializeProject = sinon
|
||||
.stub()
|
||||
.resolves(this.historyId)
|
||||
this.HistoryManager.promises.flushProject = sinon.stub()
|
||||
|
||||
return (this.ProjectEntityUpdateHandler.promises.resyncProjectHistory =
|
||||
sinon.stub())
|
||||
})
|
||||
|
||||
describe('when the history does not already exist', function () {
|
||||
beforeEach(async function () {
|
||||
this.ProjectDetailsHandler.promises.getDetails = sinon
|
||||
.stub()
|
||||
.withArgs(projectId)
|
||||
.resolves(this.project)
|
||||
this.ProjectModel.updateOne = sinon.stub().resolves({ matchedCount: 1 })
|
||||
return this.ProjectHistoryHandler.promises.ensureHistoryExistsForProject(
|
||||
projectId
|
||||
)
|
||||
})
|
||||
|
||||
it('should get any existing history id for the project', async function () {
|
||||
return this.ProjectDetailsHandler.promises.getDetails
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should initialize a new history in the v1 history service', async function () {
|
||||
return this.HistoryManager.promises.initializeProject.called.should.equal(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('should set the new history id on the project', async function () {
|
||||
return this.ProjectModel.updateOne
|
||||
.calledWith(
|
||||
{ _id: projectId, 'overleaf.history.id': { $exists: false } },
|
||||
{ 'overleaf.history.id': this.historyId }
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should resync the project history', async function () {
|
||||
return this.ProjectEntityUpdateHandler.promises.resyncProjectHistory
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should flush the project history', async function () {
|
||||
return this.HistoryManager.promises.flushProject
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the history already exists', function () {
|
||||
beforeEach(function () {
|
||||
this.project.overleaf = { history: { id: 1234 } }
|
||||
this.ProjectDetailsHandler.promises.getDetails = sinon
|
||||
.stub()
|
||||
.withArgs(projectId)
|
||||
.resolves(this.project)
|
||||
this.ProjectModel.updateOne = sinon.stub().resolves({ matchedCount: 1 })
|
||||
return this.ProjectHistoryHandler.promises.ensureHistoryExistsForProject(
|
||||
projectId
|
||||
)
|
||||
})
|
||||
|
||||
it('should get any existing history id for the project', async function () {
|
||||
return this.ProjectDetailsHandler.promises.getDetails
|
||||
.calledWith(projectId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not initialize a new history in the v1 history service', async function () {
|
||||
return this.HistoryManager.promises.initializeProject.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('should not set the new history id on the project', async function () {
|
||||
return this.ProjectModel.updateOne.called.should.equal(false)
|
||||
})
|
||||
|
||||
it('should not resync the project history', async function () {
|
||||
return this.ProjectEntityUpdateHandler.promises.resyncProjectHistory.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('should not flush the project history', async function () {
|
||||
return this.HistoryManager.promises.flushProject.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
138
services/web/test/unit/src/Referal/ReferalAllocator.test.mjs
Normal file
138
services/web/test/unit/src/Referal/ReferalAllocator.test.mjs
Normal file
@@ -0,0 +1,138 @@
|
||||
import { vi } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const modulePath = '../../../../app/src/Features/Referal/ReferalAllocator.mjs'
|
||||
|
||||
describe('ReferalAllocator', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
vi.doMock('../../../../app/src/models/User.js', () => ({
|
||||
User: (ctx.User = {}),
|
||||
}))
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Subscription/FeaturesUpdater.js',
|
||||
() => ({
|
||||
default: (ctx.FeaturesUpdater = {}),
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock('@overleaf/settings', () => ({
|
||||
default: (ctx.Settings = {}),
|
||||
}))
|
||||
|
||||
ctx.ReferalAllocator = (await import(modulePath)).default
|
||||
ctx.referal_id = 'referal-id-123'
|
||||
ctx.referal_medium = 'twitter'
|
||||
ctx.user_id = 'user-id-123'
|
||||
ctx.new_user_id = 'new-user-id-123'
|
||||
ctx.FeaturesUpdater.promises = {
|
||||
refreshFeatures: sinon.stub().resolves(),
|
||||
}
|
||||
ctx.User.updateOne = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves(),
|
||||
})
|
||||
ctx.User.findOne = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves({ _id: ctx.user_id }),
|
||||
})
|
||||
})
|
||||
|
||||
describe('allocate', function () {
|
||||
describe('when the referal was a bonus referal', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.referal_source = 'bonus'
|
||||
await ctx.ReferalAllocator.promises.allocate(
|
||||
ctx.referal_id,
|
||||
ctx.new_user_id,
|
||||
ctx.referal_source,
|
||||
ctx.referal_medium
|
||||
)
|
||||
})
|
||||
|
||||
it('should update the referring user with the refered users id', function (ctx) {
|
||||
ctx.User.updateOne
|
||||
.calledWith(
|
||||
{
|
||||
referal_id: ctx.referal_id,
|
||||
},
|
||||
{
|
||||
$push: {
|
||||
refered_users: ctx.new_user_id,
|
||||
},
|
||||
$inc: {
|
||||
refered_user_count: 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('find the referring users id', function (ctx) {
|
||||
ctx.User.findOne
|
||||
.calledWith({ referal_id: ctx.referal_id })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it("should refresh the user's subscription", function (ctx) {
|
||||
ctx.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(ctx.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there is no user for the referal id', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.referal_source = 'bonus'
|
||||
ctx.referal_id = 'wombat'
|
||||
ctx.User.findOne = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves(null),
|
||||
})
|
||||
await ctx.ReferalAllocator.promises.allocate(
|
||||
ctx.referal_id,
|
||||
ctx.new_user_id,
|
||||
ctx.referal_source,
|
||||
ctx.referal_medium
|
||||
)
|
||||
})
|
||||
|
||||
it('should find the referring users id', function (ctx) {
|
||||
ctx.User.findOne
|
||||
.calledWith({ referal_id: ctx.referal_id })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not update the referring user with the refered users id', function (ctx) {
|
||||
ctx.User.updateOne.called.should.equal(false)
|
||||
})
|
||||
|
||||
it('should not assign the user a bonus', function (ctx) {
|
||||
ctx.FeaturesUpdater.promises.refreshFeatures.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the referal is not a bonus referal', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.referal_source = 'public_share'
|
||||
await ctx.ReferalAllocator.promises.allocate(
|
||||
ctx.referal_id,
|
||||
ctx.new_user_id,
|
||||
ctx.referal_source,
|
||||
ctx.referal_medium
|
||||
)
|
||||
})
|
||||
|
||||
it('should not update the referring user with the refered users id', function (ctx) {
|
||||
ctx.User.updateOne.called.should.equal(false)
|
||||
})
|
||||
|
||||
it('find the referring users id', function (ctx) {
|
||||
ctx.User.findOne
|
||||
.calledWith({ referal_id: ctx.referal_id })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not assign the user a bonus', function (ctx) {
|
||||
ctx.FeaturesUpdater.promises.refreshFeatures.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,133 +0,0 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = require('path').join(
|
||||
__dirname,
|
||||
'../../../../app/src/Features/Referal/ReferalAllocator.js'
|
||||
)
|
||||
|
||||
describe('ReferalAllocator', function () {
|
||||
beforeEach(function () {
|
||||
this.ReferalAllocator = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'../../models/User': {
|
||||
User: (this.User = {}),
|
||||
},
|
||||
'../Subscription/FeaturesUpdater': (this.FeaturesUpdater = {}),
|
||||
'@overleaf/settings': (this.Settings = {}),
|
||||
},
|
||||
})
|
||||
this.referal_id = 'referal-id-123'
|
||||
this.referal_medium = 'twitter'
|
||||
this.user_id = 'user-id-123'
|
||||
this.new_user_id = 'new-user-id-123'
|
||||
this.FeaturesUpdater.promises = {
|
||||
refreshFeatures: sinon.stub().resolves(),
|
||||
}
|
||||
this.User.updateOne = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves(),
|
||||
})
|
||||
this.User.findOne = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves({ _id: this.user_id }),
|
||||
})
|
||||
})
|
||||
|
||||
describe('allocate', function () {
|
||||
describe('when the referal was a bonus referal', function () {
|
||||
beforeEach(async function () {
|
||||
this.referal_source = 'bonus'
|
||||
await this.ReferalAllocator.promises.allocate(
|
||||
this.referal_id,
|
||||
this.new_user_id,
|
||||
this.referal_source,
|
||||
this.referal_medium
|
||||
)
|
||||
})
|
||||
|
||||
it('should update the referring user with the refered users id', function () {
|
||||
this.User.updateOne
|
||||
.calledWith(
|
||||
{
|
||||
referal_id: this.referal_id,
|
||||
},
|
||||
{
|
||||
$push: {
|
||||
refered_users: this.new_user_id,
|
||||
},
|
||||
$inc: {
|
||||
refered_user_count: 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('find the referring users id', function () {
|
||||
this.User.findOne
|
||||
.calledWith({ referal_id: this.referal_id })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it("should refresh the user's subscription", function () {
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there is no user for the referal id', function () {
|
||||
beforeEach(async function () {
|
||||
this.referal_source = 'bonus'
|
||||
this.referal_id = 'wombat'
|
||||
this.User.findOne = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves(null),
|
||||
})
|
||||
await this.ReferalAllocator.promises.allocate(
|
||||
this.referal_id,
|
||||
this.new_user_id,
|
||||
this.referal_source,
|
||||
this.referal_medium
|
||||
)
|
||||
})
|
||||
|
||||
it('should find the referring users id', function () {
|
||||
this.User.findOne
|
||||
.calledWith({ referal_id: this.referal_id })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not update the referring user with the refered users id', function () {
|
||||
this.User.updateOne.called.should.equal(false)
|
||||
})
|
||||
|
||||
it('should not assign the user a bonus', function () {
|
||||
this.FeaturesUpdater.promises.refreshFeatures.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the referal is not a bonus referal', function () {
|
||||
beforeEach(async function () {
|
||||
this.referal_source = 'public_share'
|
||||
await this.ReferalAllocator.promises.allocate(
|
||||
this.referal_id,
|
||||
this.new_user_id,
|
||||
this.referal_source,
|
||||
this.referal_medium
|
||||
)
|
||||
})
|
||||
|
||||
it('should not update the referring user with the refered users id', function () {
|
||||
this.User.updateOne.called.should.equal(false)
|
||||
})
|
||||
|
||||
it('find the referring users id', function () {
|
||||
this.User.findOne
|
||||
.calledWith({ referal_id: this.referal_id })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not assign the user a bonus', function () {
|
||||
this.FeaturesUpdater.promises.refreshFeatures.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,89 @@
|
||||
import { vi } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
import MockResponse from '../helpers/MockResponse.js'
|
||||
import MockRequest from '../helpers/MockRequest.js'
|
||||
|
||||
const modulePath = '../../../../app/src/Features/SplitTests/SplitTestMiddleware'
|
||||
|
||||
describe('SplitTestMiddleware', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/SplitTests/SplitTestHandler.js',
|
||||
() => ({
|
||||
default: (ctx.SplitTestHandler = {
|
||||
promises: {
|
||||
getAssignment: sinon.stub().resolves(),
|
||||
},
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
ctx.SplitTestMiddleware = (await import(modulePath)).default
|
||||
|
||||
ctx.req = new MockRequest()
|
||||
ctx.res = new MockResponse()
|
||||
ctx.next = sinon.stub()
|
||||
})
|
||||
|
||||
it('assign multiple split test variants in locals', async function (ctx) {
|
||||
ctx.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(ctx.req, 'ui-overhaul')
|
||||
.resolves({
|
||||
variant: 'default',
|
||||
})
|
||||
ctx.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(ctx.req, 'other-test')
|
||||
.resolves({
|
||||
variant: 'foobar',
|
||||
})
|
||||
|
||||
const middleware = ctx.SplitTestMiddleware.loadAssignmentsInLocals([
|
||||
'ui-overhaul',
|
||||
'other-test',
|
||||
])
|
||||
await middleware(ctx.req, ctx.res, ctx.next)
|
||||
|
||||
sinon.assert.calledWith(
|
||||
ctx.SplitTestHandler.promises.getAssignment,
|
||||
ctx.req,
|
||||
ctx.res,
|
||||
'ui-overhaul'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
ctx.SplitTestHandler.promises.getAssignment,
|
||||
ctx.req,
|
||||
ctx.res,
|
||||
'other-test'
|
||||
)
|
||||
sinon.assert.calledOnce(ctx.next)
|
||||
})
|
||||
|
||||
it('assign no split test variant in locals', async function (ctx) {
|
||||
const middleware = ctx.SplitTestMiddleware.loadAssignmentsInLocals([])
|
||||
|
||||
await middleware(ctx.req, ctx.res, ctx.next)
|
||||
|
||||
sinon.assert.notCalled(ctx.SplitTestHandler.promises.getAssignment)
|
||||
sinon.assert.calledOnce(ctx.next)
|
||||
})
|
||||
|
||||
it('exception thrown by assignment does not fail the request', async function (ctx) {
|
||||
ctx.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(ctx.req, ctx.res, 'some-test')
|
||||
.throws(new Error('failure'))
|
||||
|
||||
const middleware = ctx.SplitTestMiddleware.loadAssignmentsInLocals([
|
||||
'some-test',
|
||||
])
|
||||
|
||||
await middleware(ctx.req, ctx.res, ctx.next)
|
||||
|
||||
sinon.assert.calledWith(
|
||||
ctx.SplitTestHandler.promises.getAssignment,
|
||||
ctx.req,
|
||||
ctx.res,
|
||||
'some-test'
|
||||
)
|
||||
sinon.assert.calledOnce(ctx.next)
|
||||
})
|
||||
})
|
||||
@@ -1,89 +0,0 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const path = require('path')
|
||||
const modulePath = path.join(
|
||||
__dirname,
|
||||
'../../../../app/src/Features/SplitTests/SplitTestMiddleware'
|
||||
)
|
||||
const sinon = require('sinon')
|
||||
const MockResponse = require('../helpers/MockResponse')
|
||||
const MockRequest = require('../helpers/MockRequest')
|
||||
|
||||
describe('SplitTestMiddleware', function () {
|
||||
beforeEach(function () {
|
||||
this.SplitTestMiddleware = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'./SplitTestHandler': (this.SplitTestHandler = {
|
||||
promises: {
|
||||
getAssignment: sinon.stub().resolves(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
this.req = new MockRequest()
|
||||
this.res = new MockResponse()
|
||||
this.next = sinon.stub()
|
||||
})
|
||||
|
||||
it('assign multiple split test variants in locals', async function () {
|
||||
this.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(this.req, 'ui-overhaul')
|
||||
.resolves({
|
||||
variant: 'default',
|
||||
})
|
||||
this.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(this.req, 'other-test')
|
||||
.resolves({
|
||||
variant: 'foobar',
|
||||
})
|
||||
|
||||
const middleware = this.SplitTestMiddleware.loadAssignmentsInLocals([
|
||||
'ui-overhaul',
|
||||
'other-test',
|
||||
])
|
||||
await middleware(this.req, this.res, this.next)
|
||||
|
||||
sinon.assert.calledWith(
|
||||
this.SplitTestHandler.promises.getAssignment,
|
||||
this.req,
|
||||
this.res,
|
||||
'ui-overhaul'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.SplitTestHandler.promises.getAssignment,
|
||||
this.req,
|
||||
this.res,
|
||||
'other-test'
|
||||
)
|
||||
sinon.assert.calledOnce(this.next)
|
||||
})
|
||||
|
||||
it('assign no split test variant in locals', async function () {
|
||||
const middleware = this.SplitTestMiddleware.loadAssignmentsInLocals([])
|
||||
|
||||
await middleware(this.req, this.res, this.next)
|
||||
|
||||
sinon.assert.notCalled(this.SplitTestHandler.promises.getAssignment)
|
||||
sinon.assert.calledOnce(this.next)
|
||||
})
|
||||
|
||||
it('exception thrown by assignment does not fail the request', async function () {
|
||||
this.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(this.req, this.res, 'some-test')
|
||||
.throws(new Error('failure'))
|
||||
|
||||
const middleware = this.SplitTestMiddleware.loadAssignmentsInLocals([
|
||||
'some-test',
|
||||
])
|
||||
|
||||
await middleware(this.req, this.res, this.next)
|
||||
|
||||
sinon.assert.calledWith(
|
||||
this.SplitTestHandler.promises.getAssignment,
|
||||
this.req,
|
||||
this.res,
|
||||
'some-test'
|
||||
)
|
||||
sinon.assert.calledOnce(this.next)
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user