first commit
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { expect } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = require('path').join(
|
||||
__dirname,
|
||||
'../../../../app/src/Features/Notifications/NotificationsBuilder.js'
|
||||
)
|
||||
|
||||
describe('NotificationsBuilder', function () {
|
||||
const userId = '123nd3ijdks'
|
||||
|
||||
beforeEach(function () {
|
||||
this.handler = { createNotification: sinon.stub().callsArgWith(6) }
|
||||
this.settings = { apis: { v1: { url: 'v1.url', user: '', pass: '' } } }
|
||||
this.request = sinon.stub()
|
||||
this.controller = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'./NotificationsHandler': this.handler,
|
||||
'@overleaf/settings': this.settings,
|
||||
request: this.request,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
describe('dropboxUnlinkedDueToLapsedReconfirmation', function (done) {
|
||||
it('should create the notification', function (done) {
|
||||
this.controller
|
||||
.dropboxUnlinkedDueToLapsedReconfirmation(userId)
|
||||
.create(error => {
|
||||
expect(error).to.not.exist
|
||||
expect(this.handler.createNotification).to.have.been.calledWith(
|
||||
userId,
|
||||
'drobox-unlinked-due-to-lapsed-reconfirmation',
|
||||
'notification_dropbox_unlinked_due_to_lapsed_reconfirmation',
|
||||
{},
|
||||
null,
|
||||
true
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
describe('NotificationsHandler error', function () {
|
||||
let anError
|
||||
beforeEach(function () {
|
||||
anError = new Error('oops')
|
||||
this.handler.createNotification.yields(anError)
|
||||
})
|
||||
it('should return errors from NotificationsHandler', function (done) {
|
||||
this.controller
|
||||
.dropboxUnlinkedDueToLapsedReconfirmation(userId)
|
||||
.create(error => {
|
||||
expect(error).to.exist
|
||||
expect(error).to.deep.equal(anError)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('groupInvitation', function (done) {
|
||||
const subscriptionId = '123123bcabca'
|
||||
beforeEach(function () {
|
||||
this.invite = {
|
||||
token: '123123abcabc',
|
||||
inviterName: 'Mr Overleaf',
|
||||
managedUsersEnabled: false,
|
||||
}
|
||||
})
|
||||
|
||||
it('should create the notification', function (done) {
|
||||
this.controller
|
||||
.groupInvitation(
|
||||
userId,
|
||||
subscriptionId,
|
||||
this.invite.managedUsersEnabled
|
||||
)
|
||||
.create(this.invite, error => {
|
||||
expect(error).to.not.exist
|
||||
expect(this.handler.createNotification).to.have.been.calledWith(
|
||||
userId,
|
||||
`groupInvitation-${subscriptionId}-${userId}`,
|
||||
'notification_group_invitation',
|
||||
{
|
||||
token: this.invite.token,
|
||||
inviterName: this.invite.inviterName,
|
||||
managedUsersEnabled: this.invite.managedUsersEnabled,
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('ipMatcherAffiliation', function () {
|
||||
describe('with portal and with SSO', function () {
|
||||
beforeEach(function () {
|
||||
this.body = {
|
||||
id: 1,
|
||||
name: 'stanford',
|
||||
enrolment_ad_html: 'v1 ad content',
|
||||
is_university: true,
|
||||
portal_slug: null,
|
||||
sso_enabled: false,
|
||||
}
|
||||
this.request.callsArgWith(1, null, { statusCode: 200 }, this.body)
|
||||
})
|
||||
|
||||
it('should call v1 and create affiliation notifications', function (done) {
|
||||
const ip = '192.168.0.1'
|
||||
this.controller.ipMatcherAffiliation(userId).create(ip, callback => {
|
||||
this.request.calledOnce.should.equal(true)
|
||||
const expectedOpts = {
|
||||
institutionId: this.body.id,
|
||||
university_name: this.body.name,
|
||||
content: this.body.enrolment_ad_html,
|
||||
ssoEnabled: false,
|
||||
portalPath: undefined,
|
||||
}
|
||||
this.handler.createNotification
|
||||
.calledWith(
|
||||
userId,
|
||||
`ip-matched-affiliation-${this.body.id}`,
|
||||
'notification_ip_matched_affiliation',
|
||||
expectedOpts
|
||||
)
|
||||
.should.equal(true)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('without portal and without SSO', function () {
|
||||
beforeEach(function () {
|
||||
this.body = {
|
||||
id: 1,
|
||||
name: 'stanford',
|
||||
enrolment_ad_html: 'v1 ad content',
|
||||
is_university: true,
|
||||
portal_slug: 'stanford',
|
||||
sso_enabled: true,
|
||||
}
|
||||
this.request.callsArgWith(1, null, { statusCode: 200 }, this.body)
|
||||
})
|
||||
|
||||
it('should call v1 and create affiliation notifications', function (done) {
|
||||
const ip = '192.168.0.1'
|
||||
this.controller.ipMatcherAffiliation(userId).create(ip, callback => {
|
||||
this.request.calledOnce.should.equal(true)
|
||||
const expectedOpts = {
|
||||
institutionId: this.body.id,
|
||||
university_name: this.body.name,
|
||||
content: this.body.enrolment_ad_html,
|
||||
ssoEnabled: true,
|
||||
portalPath: '/edu/stanford',
|
||||
}
|
||||
this.handler.createNotification
|
||||
.calledWith(
|
||||
userId,
|
||||
`ip-matched-affiliation-${this.body.id}`,
|
||||
'notification_ip_matched_affiliation',
|
||||
expectedOpts
|
||||
)
|
||||
.should.equal(true)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@@ -0,0 +1,66 @@
|
||||
import esmock from 'esmock'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const modulePath = new URL(
|
||||
'../../../../app/src/Features/Notifications/NotificationsController.mjs',
|
||||
import.meta.url
|
||||
).pathname
|
||||
|
||||
describe('NotificationsController', function () {
|
||||
const userId = '123nd3ijdks'
|
||||
const notificationId = '123njdskj9jlk'
|
||||
|
||||
beforeEach(async function () {
|
||||
this.handler = {
|
||||
getUserNotifications: sinon.stub().callsArgWith(1),
|
||||
markAsRead: sinon.stub().callsArgWith(2),
|
||||
}
|
||||
this.req = {
|
||||
params: {
|
||||
notificationId,
|
||||
},
|
||||
session: {
|
||||
user: {
|
||||
_id: userId,
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
translate() {},
|
||||
},
|
||||
}
|
||||
this.AuthenticationController = {
|
||||
getLoggedInUserId: sinon.stub().returns(this.req.session.user._id),
|
||||
}
|
||||
this.controller = await esmock.strict(modulePath, {
|
||||
'../../../../app/src/Features/Notifications/NotificationsHandler':
|
||||
this.handler,
|
||||
'../../../../app/src/Features/Authentication/AuthenticationController':
|
||||
this.AuthenticationController,
|
||||
})
|
||||
})
|
||||
|
||||
it('should ask the handler for all unread notifications', function (done) {
|
||||
const allNotifications = [{ _id: notificationId, user_id: userId }]
|
||||
this.handler.getUserNotifications = sinon
|
||||
.stub()
|
||||
.callsArgWith(1, null, allNotifications)
|
||||
this.controller.getAllUnreadNotifications(this.req, {
|
||||
json: body => {
|
||||
body.should.deep.equal(allNotifications)
|
||||
this.handler.getUserNotifications.calledWith(userId).should.equal(true)
|
||||
done()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should send a delete request when a delete has been received to mark a notification', function (done) {
|
||||
this.controller.markNotificationAsRead(this.req, {
|
||||
sendStatus: () => {
|
||||
this.handler.markAsRead
|
||||
.calledWith(userId, notificationId)
|
||||
.should.equal(true)
|
||||
done()
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
@@ -0,0 +1,179 @@
|
||||
/* eslint-disable
|
||||
n/handle-callback-err,
|
||||
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
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { assert } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = require('path').join(
|
||||
__dirname,
|
||||
'../../../../app/src/Features/Notifications/NotificationsHandler.js'
|
||||
)
|
||||
const _ = require('lodash')
|
||||
|
||||
describe('NotificationsHandler', function () {
|
||||
const userId = '123nd3ijdks'
|
||||
const notificationId = '123njdskj9jlk'
|
||||
const notificationUrl = 'notification.overleaf.testing'
|
||||
|
||||
beforeEach(function () {
|
||||
this.request = sinon.stub().callsArgWith(1)
|
||||
return (this.handler = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'@overleaf/settings': {
|
||||
apis: { notifications: { url: notificationUrl } },
|
||||
},
|
||||
request: this.request,
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
describe('getUserNotifications', function () {
|
||||
it('should get unread notifications', function (done) {
|
||||
const stubbedNotifications = [{ _id: notificationId, user_id: userId }]
|
||||
this.request.callsArgWith(
|
||||
1,
|
||||
null,
|
||||
{ statusCode: 200 },
|
||||
stubbedNotifications
|
||||
)
|
||||
return this.handler.getUserNotifications(
|
||||
userId,
|
||||
(err, unreadNotifications) => {
|
||||
stubbedNotifications.should.deep.equal(unreadNotifications)
|
||||
const getOpts = {
|
||||
uri: `${notificationUrl}/user/${userId}`,
|
||||
json: true,
|
||||
timeout: 1000,
|
||||
method: 'GET',
|
||||
}
|
||||
this.request.calledWith(getOpts).should.equal(true)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should return empty arrays if there are no notifications', function () {
|
||||
this.request.callsArgWith(1, null, { statusCode: 200 }, null)
|
||||
return this.handler.getUserNotifications(
|
||||
userId,
|
||||
(err, unreadNotifications) => {
|
||||
return unreadNotifications.length.should.equal(0)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('markAsRead', function () {
|
||||
beforeEach(function () {
|
||||
return (this.key = 'some key here')
|
||||
})
|
||||
|
||||
it('should send a delete request when a delete has been received to mark a notification', function (done) {
|
||||
return this.handler.markAsReadWithKey(userId, this.key, () => {
|
||||
const opts = {
|
||||
uri: `${notificationUrl}/user/${userId}`,
|
||||
json: {
|
||||
key: this.key,
|
||||
},
|
||||
timeout: 1000,
|
||||
method: 'DELETE',
|
||||
}
|
||||
this.request.calledWith(opts).should.equal(true)
|
||||
return done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('createNotification', function () {
|
||||
beforeEach(function () {
|
||||
this.key = 'some key here'
|
||||
this.messageOpts = { value: 12344 }
|
||||
this.templateKey = 'renderThisHtml'
|
||||
return (this.expiry = null)
|
||||
})
|
||||
|
||||
it('should post the message over', function (done) {
|
||||
return this.handler.createNotification(
|
||||
userId,
|
||||
this.key,
|
||||
this.templateKey,
|
||||
this.messageOpts,
|
||||
this.expiry,
|
||||
() => {
|
||||
const args = this.request.args[0][0]
|
||||
args.uri.should.equal(`${notificationUrl}/user/${userId}`)
|
||||
args.timeout.should.equal(1000)
|
||||
const expectedJson = {
|
||||
key: this.key,
|
||||
templateKey: this.templateKey,
|
||||
messageOpts: this.messageOpts,
|
||||
forceCreate: true,
|
||||
}
|
||||
assert.deepEqual(args.json, expectedJson)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('when expiry date is supplied', function () {
|
||||
beforeEach(function () {
|
||||
this.key = 'some key here'
|
||||
this.messageOpts = { value: 12344 }
|
||||
this.templateKey = 'renderThisHtml'
|
||||
return (this.expiry = new Date())
|
||||
})
|
||||
|
||||
it('should post the message over with expiry field', function (done) {
|
||||
return this.handler.createNotification(
|
||||
userId,
|
||||
this.key,
|
||||
this.templateKey,
|
||||
this.messageOpts,
|
||||
this.expiry,
|
||||
() => {
|
||||
const args = this.request.args[0][0]
|
||||
args.uri.should.equal(`${notificationUrl}/user/${userId}`)
|
||||
args.timeout.should.equal(1000)
|
||||
const expectedJson = {
|
||||
key: this.key,
|
||||
templateKey: this.templateKey,
|
||||
messageOpts: this.messageOpts,
|
||||
expires: this.expiry,
|
||||
forceCreate: true,
|
||||
}
|
||||
assert.deepEqual(args.json, expectedJson)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('markAsReadByKeyOnly', function () {
|
||||
beforeEach(function () {
|
||||
return (this.key = 'some key here')
|
||||
})
|
||||
|
||||
it('should send a delete request when a delete has been received to mark a notification', function (done) {
|
||||
return this.handler.markAsReadByKeyOnly(this.key, () => {
|
||||
const opts = {
|
||||
uri: `${notificationUrl}/key/${this.key}`,
|
||||
timeout: 1000,
|
||||
method: 'DELETE',
|
||||
}
|
||||
this.request.calledWith(opts).should.equal(true)
|
||||
return done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user