mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
add saml acceptance tests. get/set entitlement.
GitOrigin-RevId: 65721aadb91678eafaf5a214a2921fe3dd276efa
This commit is contained in:
parent
de8ac8ace7
commit
849f21fde3
6 changed files with 230 additions and 25 deletions
|
@ -23,6 +23,7 @@ const logger = require('logger-sharelatex')
|
|||
const ReferalFeatures = require('../Referal/ReferalFeatures')
|
||||
const V1SubscriptionManager = require('./V1SubscriptionManager')
|
||||
const InstitutionsFeatures = require('../Institutions/InstitutionsFeatures')
|
||||
const UserGetter = require('../User/UserGetter')
|
||||
|
||||
const oneMonthInSeconds = 60 * 60 * 24 * 30
|
||||
|
||||
|
@ -47,6 +48,9 @@ module.exports = FeaturesUpdater = {
|
|||
},
|
||||
bonusFeatures(cb) {
|
||||
return ReferalFeatures.getBonusFeatures(user_id, cb)
|
||||
},
|
||||
samlFeatures(cb) {
|
||||
return FeaturesUpdater._getSamlFeatures(user_id, cb)
|
||||
}
|
||||
}
|
||||
return async.series(jobs, function(err, results) {
|
||||
|
@ -63,7 +67,8 @@ module.exports = FeaturesUpdater = {
|
|||
groupFeatureSets,
|
||||
institutionFeatures,
|
||||
v1Features,
|
||||
bonusFeatures
|
||||
bonusFeatures,
|
||||
samlFeatures
|
||||
} = results
|
||||
logger.log(
|
||||
{
|
||||
|
@ -72,7 +77,8 @@ module.exports = FeaturesUpdater = {
|
|||
groupFeatureSets,
|
||||
institutionFeatures,
|
||||
v1Features,
|
||||
bonusFeatures
|
||||
bonusFeatures,
|
||||
samlFeatures
|
||||
},
|
||||
'merging user features'
|
||||
)
|
||||
|
@ -80,7 +86,8 @@ module.exports = FeaturesUpdater = {
|
|||
individualFeatures,
|
||||
institutionFeatures,
|
||||
v1Features,
|
||||
bonusFeatures
|
||||
bonusFeatures,
|
||||
samlFeatures
|
||||
])
|
||||
const features = _.reduce(
|
||||
featureSets,
|
||||
|
@ -113,6 +120,30 @@ module.exports = FeaturesUpdater = {
|
|||
)
|
||||
},
|
||||
|
||||
_getSamlFeatures(user_id, callback) {
|
||||
UserGetter.getUser(user_id, (err, user) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
if (
|
||||
!user ||
|
||||
!Array.isArray(user.samlIdentifiers) ||
|
||||
!user.samlIdentifiers.length
|
||||
) {
|
||||
return callback(null, {})
|
||||
}
|
||||
for (const samlIdentifier of user.samlIdentifiers) {
|
||||
if (samlIdentifier && samlIdentifier.hasEntitlement) {
|
||||
return callback(
|
||||
null,
|
||||
FeaturesUpdater._planCodeToFeatures('professional')
|
||||
)
|
||||
}
|
||||
}
|
||||
return callback(null, {})
|
||||
})
|
||||
},
|
||||
|
||||
_getV1Features(user_id, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, features) {}
|
||||
|
|
|
@ -6,8 +6,9 @@ const { User } = require('../../models/User')
|
|||
const UserGetter = require('../User/UserGetter')
|
||||
const UserUpdater = require('../User/UserUpdater')
|
||||
|
||||
function _addIdentifier(userId, externalUserId, providerId) {
|
||||
function _addIdentifier(userId, externalUserId, providerId, hasEntitlement) {
|
||||
providerId = providerId.toString()
|
||||
hasEntitlement = !!hasEntitlement
|
||||
const query = {
|
||||
_id: userId,
|
||||
'samlIdentifiers.providerId': {
|
||||
|
@ -17,6 +18,7 @@ function _addIdentifier(userId, externalUserId, providerId) {
|
|||
const update = {
|
||||
$push: {
|
||||
samlIdentifiers: {
|
||||
hasEntitlement,
|
||||
externalUserId,
|
||||
providerId
|
||||
}
|
||||
|
@ -113,8 +115,12 @@ function _sendUnlinkedEmail(primaryEmail, providerName) {
|
|||
|
||||
async function getUser(providerId, externalUserId) {
|
||||
if (providerId == null || externalUserId == null) {
|
||||
throw new Error('invalid arguments')
|
||||
throw new Error(
|
||||
`invalid arguments: providerId: ${providerId}, externalUserId: ${externalUserId}`
|
||||
)
|
||||
}
|
||||
providerId = providerId.toString()
|
||||
externalUserId = externalUserId.toString()
|
||||
const query = _getUserQuery(providerId, externalUserId)
|
||||
let user = await User.findOne(query).exec()
|
||||
if (!user) {
|
||||
|
@ -128,14 +134,16 @@ async function linkAccounts(
|
|||
externalUserId,
|
||||
institutionEmail,
|
||||
providerId,
|
||||
providerName
|
||||
providerName,
|
||||
hasEntitlement
|
||||
) {
|
||||
await _addIdentifier(userId, externalUserId, providerId)
|
||||
await _addIdentifier(userId, externalUserId, providerId, hasEntitlement)
|
||||
await _addInstitutionEmail(userId, institutionEmail, providerId)
|
||||
await _sendLinkedEmail(userId, providerName)
|
||||
}
|
||||
|
||||
async function unlinkAccounts(userId, primaryEmail, providerId, providerName) {
|
||||
providerId = providerId.toString()
|
||||
const query = {
|
||||
_id: userId
|
||||
}
|
||||
|
@ -150,10 +158,55 @@ async function unlinkAccounts(userId, primaryEmail, providerId, providerName) {
|
|||
_sendUnlinkedEmail(primaryEmail, providerName)
|
||||
}
|
||||
|
||||
async function updateEntitlement(userId, providerId, hasEntitlement) {
|
||||
providerId = providerId.toString()
|
||||
hasEntitlement = !!hasEntitlement
|
||||
const query = {
|
||||
_id: userId,
|
||||
'samlIdentifiers.providerId': providerId.toString()
|
||||
}
|
||||
const update = {
|
||||
$set: {
|
||||
'samlIdentifiers.$.hasEntitlement': hasEntitlement
|
||||
}
|
||||
}
|
||||
await User.update(query, update).exec()
|
||||
}
|
||||
|
||||
function entitlementAttributeMatches(entitlementAttribute, entitlementMatcher) {
|
||||
if (
|
||||
typeof entitlementAttribute !== 'string' ||
|
||||
typeof entitlementMatcher !== 'string'
|
||||
) {
|
||||
return false
|
||||
}
|
||||
const entitlementRegExp = new RegExp(entitlementMatcher)
|
||||
return !!entitlementAttribute.match(entitlementRegExp)
|
||||
}
|
||||
|
||||
function userHasEntitlement(user, providerId) {
|
||||
providerId = providerId.toString()
|
||||
if (!user || !Array.isArray(user.samlIdentifiers)) {
|
||||
return false
|
||||
}
|
||||
for (const samlIdentifier of user.samlIdentifiers) {
|
||||
if (providerId && samlIdentifier.providerId !== providerId) {
|
||||
continue
|
||||
}
|
||||
if (samlIdentifier.hasEntitlement) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const SAMLIdentityManager = {
|
||||
entitlementAttributeMatches,
|
||||
getUser,
|
||||
linkAccounts,
|
||||
unlinkAccounts
|
||||
unlinkAccounts,
|
||||
updateEntitlement,
|
||||
userHasEntitlement
|
||||
}
|
||||
|
||||
module.exports = SAMLIdentityManager
|
||||
|
|
124
services/web/package-lock.json
generated
124
services/web/package-lock.json
generated
|
@ -3691,6 +3691,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
||||
"dev": true
|
||||
},
|
||||
"boolify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz",
|
||||
|
@ -4285,6 +4291,32 @@
|
|||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
|
||||
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
|
||||
},
|
||||
"cheerio": {
|
||||
"version": "1.0.0-rc.3",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
|
||||
"integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css-select": "~1.2.0",
|
||||
"dom-serializer": "~0.1.1",
|
||||
"entities": "~1.1.1",
|
||||
"htmlparser2": "^3.9.1",
|
||||
"lodash": "^4.15.0",
|
||||
"parse5": "^3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dom-serializer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
|
||||
"integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "^1.3.0",
|
||||
"entities": "^1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
|
||||
|
@ -5270,6 +5302,36 @@
|
|||
"uid-safe": "2.1.4"
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0",
|
||||
"css-what": "2.1",
|
||||
"domutils": "1.5.1",
|
||||
"nth-check": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"domutils": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
||||
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
|
||||
"dev": true
|
||||
},
|
||||
"csurf": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/csurf/-/csurf-1.9.0.tgz",
|
||||
|
@ -6285,7 +6347,6 @@
|
|||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz",
|
||||
"integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-to-primitive": "^1.1.1",
|
||||
"function-bind": "^1.1.1",
|
||||
|
@ -6298,7 +6359,6 @@
|
|||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
|
||||
"integrity": "sha512-wXsac552n5sYhgVjyFvhXLunXZFPOiT/WgP7hFhUPU5gtaUQpm9OryPwlWQUS3Qptk8iZzY/2T3J62GtC/toSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-callable": "^1.1.1",
|
||||
"is-date-object": "^1.0.1",
|
||||
|
@ -10381,8 +10441,7 @@
|
|||
"is-callable": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
|
||||
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
|
||||
},
|
||||
"is-ci": {
|
||||
"version": "1.1.0",
|
||||
|
@ -10401,8 +10460,7 @@
|
|||
"is-date-object": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
||||
"integrity": "sha512-P5rExV1phPi42ppoMWy7V63N3i173RY921l4JJ7zonMSxK+OWGPj76GD+cUKUb68l4vQXcJp2SsG+r/A4ABVzg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-P5rExV1phPi42ppoMWy7V63N3i173RY921l4JJ7zonMSxK+OWGPj76GD+cUKUb68l4vQXcJp2SsG+r/A4ABVzg=="
|
||||
},
|
||||
"is-descriptor": {
|
||||
"version": "0.1.6",
|
||||
|
@ -10655,8 +10713,7 @@
|
|||
"is-symbol": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
|
||||
"integrity": "sha512-Z1cLAG7dXM1vJv8mAGjA+XteO0YzYPwD473+qPAWKycNZxwCH/I56QIohKGYCZSB7j6tajrxi/FvOpAfqGhhRQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Z1cLAG7dXM1vJv8mAGjA+XteO0YzYPwD473+qPAWKycNZxwCH/I56QIohKGYCZSB7j6tajrxi/FvOpAfqGhhRQ=="
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
|
@ -14533,6 +14590,15 @@
|
|||
"set-blocking": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"nth-check": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
|
||||
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"null-check": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz",
|
||||
|
@ -14751,6 +14817,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"object.getownpropertydescriptors": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
|
||||
"integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.2",
|
||||
"es-abstract": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"object.omit": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
|
||||
|
@ -15400,6 +15475,15 @@
|
|||
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
|
||||
"dev": true
|
||||
},
|
||||
"parse5": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
|
||||
"integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"parseqs": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
|
||||
|
@ -20209,6 +20293,15 @@
|
|||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"util.promisify": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
|
||||
"integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.2",
|
||||
"object.getownpropertydescriptors": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
|
||||
|
@ -23347,18 +23440,19 @@
|
|||
}
|
||||
},
|
||||
"xml2js": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||
"version": "0.4.22",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz",
|
||||
"integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==",
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~9.0.1"
|
||||
"util.promisify": "~1.0.0",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ=="
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
"uuid": "^3.0.1",
|
||||
"v8-profiler-node8": "^6.0.1",
|
||||
"valid-url": "^1.0.9",
|
||||
"xml2js": "^0.4.19",
|
||||
"xml2js": "^0.4.22",
|
||||
"xregexp": "^4.2.4",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
|
@ -128,6 +128,7 @@
|
|||
"chai": "3.5.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chaid": "^1.0.2",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"clean-css-cli": "^4.2.1",
|
||||
"es6-promise": "^4.0.5",
|
||||
"eslint": "^4.18.1",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const AuthenticationManager = require('../../../../app/src/Features/Authentication/AuthenticationManager')
|
||||
const Settings = require('settings-sharelatex')
|
||||
const UserCreator = require('../../../../app/src/Features/User/UserCreator')
|
||||
const UserGetter = require('../../../../app/src/Features/User/UserGetter')
|
||||
const request = require('request-promise-native')
|
||||
|
@ -125,6 +126,29 @@ module.exports = class UserHelper {
|
|||
return new UserHelper(user)
|
||||
}
|
||||
|
||||
static async loginUser(userData) {
|
||||
if (!userData.email || !userData.password) {
|
||||
throw new Error('email and password required')
|
||||
}
|
||||
const userHelper = new UserHelper()
|
||||
const loginPath = Settings.enableLegacyLogin ? '/login/legacy' : '/login'
|
||||
await userHelper.getCsrfToken()
|
||||
const response = await userHelper.request.post(loginPath, {
|
||||
json: userData
|
||||
})
|
||||
if (response.statusCode !== 200 || response.body.redir !== '/project') {
|
||||
throw new Error('login failed')
|
||||
}
|
||||
userHelper.user = await UserGetter.promises.getUser({
|
||||
email: userData.email
|
||||
})
|
||||
if (!userHelper.user) {
|
||||
throw new Error(`user not found for email: ${userData.email}`)
|
||||
}
|
||||
|
||||
return userHelper
|
||||
}
|
||||
|
||||
static async registerUser(userData, options = {}) {
|
||||
const userHelper = new UserHelper()
|
||||
await userHelper.getCsrfToken()
|
||||
|
|
|
@ -36,7 +36,8 @@ describe('FeaturesUpdater', function() {
|
|||
'settings-sharelatex': (this.Settings = {}),
|
||||
'../Referal/ReferalFeatures': (this.ReferalFeatures = {}),
|
||||
'./V1SubscriptionManager': (this.V1SubscriptionManager = {}),
|
||||
'../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {})
|
||||
'../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
|
||||
'../User/UserGetter': (this.UserGetter = {})
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
@ -62,6 +63,7 @@ describe('FeaturesUpdater', function() {
|
|||
this.FeaturesUpdater._mergeFeatures = sinon
|
||||
.stub()
|
||||
.returns({ merged: 'features' })
|
||||
this.UserGetter.getUser = sinon.stub().yields(null, {})
|
||||
return (this.callback = sinon.stub())
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue