Merge pull request #2040 from overleaf/spd-projectinvite-tests

Ensure tests ProjectInviteTests are not dependent on previous test state

GitOrigin-RevId: 0db825789f86d2a22a8ad981d4d1875a93c83017
This commit is contained in:
Eric Mc Sween 2019-08-06 08:20:20 -04:00 committed by sharelatex
parent 2df7a8eaad
commit 5d0c6cddf6

View file

@ -1,32 +1,15 @@
/* eslint-disable
handle-callback-err,
max-len,
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
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const { expect } = require('chai')
const Async = require('async')
const User = require('./helpers/User')
const request = require('./helpers/request')
const settings = require('settings-sharelatex')
const CollaboratorsEmailHandler = require('../../../app/src/Features/Collaborators/CollaboratorsEmailHandler')
const createInvite = function(sendingUser, projectId, email, callback) {
if (callback == null) {
callback = function(err, invite) {}
}
return sendingUser.getCsrfToken(function(err) {
const createInvite = (sendingUser, projectId, email, callback) => {
sendingUser.getCsrfToken(err => {
if (err) {
return callback(err)
}
return sendingUser.request.post(
sendingUser.request.post(
{
uri: `/project/${projectId}/invite`,
json: {
@ -34,22 +17,19 @@ const createInvite = function(sendingUser, projectId, email, callback) {
privileges: 'readAndWrite'
}
},
function(err, response, body) {
(err, response, body) => {
if (err) {
return callback(err)
}
expect(response.statusCode).to.equal(200)
return callback(null, body.invite)
callback(null, body.invite)
}
)
})
}
const createProject = function(owner, projectName, callback) {
if (callback == null) {
callback = function(err, projectId, project) {}
}
return owner.createProject(projectName, function(err, projectId) {
const createProject = (owner, projectName, callback) => {
owner.createProject(projectName, (err, projectId) => {
if (err) {
throw err
}
@ -58,56 +38,47 @@ const createProject = function(owner, projectName, callback) {
name: projectName,
owner_ref: owner
}
return callback(err, projectId, fakeProject)
callback(err, projectId, fakeProject)
})
}
const createProjectAndInvite = function(owner, projectName, email, callback) {
if (callback == null) {
callback = function(err, project, invite) {}
}
return createProject(owner, projectName, function(err, projectId, project) {
const createProjectAndInvite = (owner, projectName, email, callback) => {
createProject(owner, projectName, (err, projectId, project) => {
if (err) {
return callback(err)
}
return createInvite(owner, projectId, email, function(err, invite) {
createInvite(owner, projectId, email, (err, invite) => {
if (err) {
return callback(err)
}
const link = CollaboratorsEmailHandler._buildInviteUrl(project, invite)
return callback(null, project, invite, link)
callback(null, project, invite, link)
})
})
}
const revokeInvite = function(sendingUser, projectId, inviteId, callback) {
if (callback == null) {
callback = function(err) {}
}
return sendingUser.getCsrfToken(function(err) {
const revokeInvite = (sendingUser, projectId, inviteId, callback) => {
sendingUser.getCsrfToken(err => {
if (err) {
return callback(err)
}
return sendingUser.request.delete(
sendingUser.request.delete(
{
uri: `/project/${projectId}/invite/${inviteId}`
},
function(err, response, body) {
err => {
if (err) {
return callback(err)
}
return callback(null)
callback()
}
)
})
}
// Actions
const tryFollowInviteLink = function(user, link, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
return user.request.get(
const tryFollowInviteLink = (user, link, callback) => {
user.request.get(
{
uri: link,
baseUrl: null
@ -116,11 +87,8 @@ const tryFollowInviteLink = function(user, link, callback) {
)
}
const tryAcceptInvite = function(user, invite, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
return user.request.post(
const tryAcceptInvite = (user, invite, callback) => {
user.request.post(
{
uri: `/project/${invite.projectId}/invite/token/${invite.token}/accept`,
json: {
@ -131,15 +99,12 @@ const tryAcceptInvite = function(user, invite, callback) {
)
}
const tryRegisterUser = function(user, email, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
return user.getCsrfToken(error => {
const tryRegisterUser = (user, email, callback) => {
user.getCsrfToken(error => {
if (error != null) {
return callback(error)
}
return user.request.post(
user.request.post(
{
url: '/register',
json: {
@ -152,27 +117,21 @@ const tryRegisterUser = function(user, email, callback) {
})
}
const tryFollowLoginLink = function(user, loginLink, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
return user.getCsrfToken(error => {
const tryFollowLoginLink = (user, loginLink, callback) => {
user.getCsrfToken(error => {
if (error != null) {
return callback(error)
}
return user.request.get(loginLink, callback)
user.request.get(loginLink, callback)
})
}
const tryLoginUser = function(user, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
return user.getCsrfToken(error => {
const tryLoginUser = (user, callback) => {
user.getCsrfToken(error => {
if (error != null) {
return callback(error)
}
return user.request.post(
user.request.post(
{
url: '/login',
json: {
@ -185,15 +144,12 @@ const tryLoginUser = function(user, callback) {
})
}
const tryGetInviteList = function(user, projectId, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
return user.getCsrfToken(error => {
const tryGetInviteList = (user, projectId, callback) => {
user.getCsrfToken(error => {
if (error != null) {
return callback(error)
}
return user.request.get(
user.request.get(
{
url: `/project/${projectId}/invites`,
json: true
@ -203,15 +159,12 @@ const tryGetInviteList = function(user, projectId, callback) {
})
}
const tryJoinProject = function(user, projectId, callback) {
if (callback == null) {
callback = function(err, response, body) {}
}
const tryJoinProject = (user, projectId, callback) => {
return user.getCsrfToken(error => {
if (error != null) {
return callback(error)
}
return user.request.post(
user.request.post(
{
url: `/project/${projectId}/join`,
qs: { user_id: user._id },
@ -229,174 +182,125 @@ const tryJoinProject = function(user, projectId, callback) {
}
// Expectations
const expectProjectAccess = function(user, projectId, callback) {
const expectProjectAccess = (user, projectId, callback) => {
// should have access to project
if (callback == null) {
callback = function(err, result) {}
}
return user.openProject(projectId, err => {
expect(err).to.be.oneOf([null, undefined])
return callback()
user.openProject(projectId, err => {
expect(err).not.to.exist
callback()
})
}
const expectNoProjectAccess = function(user, projectId, callback) {
const expectNoProjectAccess = (user, projectId, callback) => {
// should not have access to project page
if (callback == null) {
callback = function(err, result) {}
}
return user.openProject(projectId, err => {
user.openProject(projectId, err => {
expect(err).to.be.instanceof(Error)
return callback()
callback()
})
}
const expectInvitePage = function(user, link, callback) {
const expectInvitePage = (user, link, callback) => {
// view invite
if (callback == null) {
callback = function(err, result) {}
}
return tryFollowInviteLink(user, link, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
tryFollowInviteLink(user, link, (err, response, body) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
expect(body).to.match(new RegExp('<title>Project Invite - .*</title>'))
return callback()
callback()
})
}
const expectInvalidInvitePage = function(user, link, callback) {
const expectInvalidInvitePage = (user, link, callback) => {
// view invalid invite
if (callback == null) {
callback = function(err, result) {}
}
return tryFollowInviteLink(user, link, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
tryFollowInviteLink(user, link, (err, response, body) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
expect(body).to.match(new RegExp('<title>Invalid Invite - .*</title>'))
return callback()
callback()
})
}
const expectInviteRedirectToRegister = function(user, link, callback) {
const expectInviteRedirectToRegister = (user, link, callback) => {
// view invite, redirect to `/register`
if (callback == null) {
callback = function(err, result) {}
}
return tryFollowInviteLink(user, link, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
tryFollowInviteLink(user, link, (err, response) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(302)
expect(response.headers.location).to.match(new RegExp('^/register.*$'))
// follow redirect to register page and extract the redirectUrl from form
return user.request.get(response.headers.location, (err, response, body) =>
callback(null)
)
callback()
})
}
const expectLoginPage = function(user, callback) {
if (callback == null) {
callback = function(err, result) {}
}
return tryFollowLoginLink(user, '/login', function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
const expectLoginPage = (user, callback) => {
tryFollowLoginLink(user, '/login', (err, response, body) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
expect(body).to.match(new RegExp('<title>Login - .*</title>'))
return callback(null)
callback()
})
}
const expectLoginRedirectToInvite = function(user, link, callback) {
if (callback == null) {
callback = function(err, result) {}
}
return tryLoginUser(user, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
const expectLoginRedirectToInvite = (user, link, callback) => {
tryLoginUser(user, (err, response) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
return callback(null, null)
callback()
})
}
const expectRegistrationRedirectToInvite = function(
user,
email,
link,
callback
) {
if (callback == null) {
callback = function(err, result) {}
}
return tryRegisterUser(user, email, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
const expectRegistrationRedirectToInvite = (user, email, link, callback) => {
tryRegisterUser(user, email, (err, response) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
return callback(null, null)
callback()
})
}
const expectInviteRedirectToProject = function(user, link, invite, callback) {
const expectInviteRedirectToProject = (user, link, invite, callback) => {
// view invite, redirect straight to project
if (callback == null) {
callback = function(err, result) {}
}
return tryFollowInviteLink(user, link, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
tryFollowInviteLink(user, link, (err, response) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(302)
expect(response.headers.location).to.equal(`/project/${invite.projectId}`)
return callback()
callback()
})
}
const expectAcceptInviteAndRedirect = function(user, invite, callback) {
const expectAcceptInviteAndRedirect = (user, invite, callback) => {
// should accept the invite and redirect to project
if (callback == null) {
callback = function(err, result) {}
}
return tryAcceptInvite(user, invite, (err, response, body) => {
expect(err).to.be.oneOf([null, undefined])
tryAcceptInvite(user, invite, (err, response) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(302)
expect(response.headers.location).to.equal(`/project/${invite.projectId}`)
return callback()
callback()
})
}
const expectInviteListCount = function(user, projectId, count, callback) {
if (callback == null) {
callback = function(err) {}
}
return tryGetInviteList(user, projectId, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
const expectInviteListCount = (user, projectId, count, callback) => {
tryGetInviteList(user, projectId, (err, response, body) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
expect(body).to.have.all.keys(['invites'])
expect(body.invites.length).to.equal(count)
return callback()
callback()
})
}
const expectInvitesInJoinProjectCount = function(
user,
projectId,
count,
callback
) {
if (callback == null) {
callback = function(err, result) {}
}
return tryJoinProject(user, projectId, function(err, response, body) {
expect(err).to.be.oneOf([null, undefined])
const expectInvitesInJoinProjectCount = (user, projectId, count, callback) => {
tryJoinProject(user, projectId, (err, response, body) => {
expect(err).not.to.exist
expect(response.statusCode).to.equal(200)
expect(body.project).to.contain.keys(['invites'])
expect(body.project.invites.length).to.equal(count)
return callback()
callback()
})
}
describe('ProjectInviteTests', function() {
before(function(done) {
describe('ProjectInviteTests', () => {
beforeEach(done => {
this.sendingUser = new User()
this.user = new User()
this.site_admin = new User({ email: 'admin@example.com' })
this.email = 'smoketestuser@example.com'
this.projectName = 'sharing test'
return Async.series(
Async.series(
[
cb => this.user.ensureUserExists(cb),
cb => this.sendingUser.login(cb),
@ -406,54 +310,34 @@ describe('ProjectInviteTests', function() {
)
})
describe('creating invites', function() {
beforeEach(function(done) {
describe('creating invites', () => {
beforeEach(() => {
this.projectName = 'wat'
this.projectId = null
this.fakeProject = null
return done()
})
describe('creating two invites', function() {
beforeEach(function(done) {
return Async.series(
[
cb => {
return createProject(
this.sendingUser,
this.projectName,
(err, projectId, project) => {
this.projectId = projectId
this.fakeProject = project
return cb()
}
)
}
],
done
describe('creating two invites', () => {
beforeEach(done => {
createProject(
this.sendingUser,
this.projectName,
(err, projectId, project) => {
expect(err).not.to.exist
this.projectId = projectId
this.fakeProject = project
done()
}
)
})
afterEach(function(done) {
return Async.series(
[
cb => this.sendingUser.deleteProject(this.projectId, cb),
cb => this.sendingUser.deleteProject(this.projectId, cb)
],
done
)
})
it('should allow the project owner to create and remove invites', function(done) {
this.invite = null
return Async.series(
it('should allow the project owner to create and remove invites', done => {
Async.series(
[
cb => expectProjectAccess(this.sendingUser, this.projectId, cb),
cb =>
expectInviteListCount(this.sendingUser, this.projectId, 0, cb),
// create invite, check invite list count
cb => {
return createInvite(
createInvite(
this.sendingUser,
this.projectId,
this.email,
@ -462,7 +346,7 @@ describe('ProjectInviteTests', function() {
return cb(err)
}
this.invite = invite
return cb()
cb()
}
)
},
@ -479,7 +363,7 @@ describe('ProjectInviteTests', function() {
expectInviteListCount(this.sendingUser, this.projectId, 0, cb),
// and a second time
cb => {
return createInvite(
createInvite(
this.sendingUser,
this.projectId,
this.email,
@ -488,7 +372,7 @@ describe('ProjectInviteTests', function() {
return cb(err)
}
this.invite = invite
return cb()
cb()
}
)
},
@ -524,17 +408,15 @@ describe('ProjectInviteTests', function() {
)
})
it('should allow the project owner to create many invites at once', function(done) {
this.inviteOne = null
this.inviteTwo = null
return Async.series(
it('should allow the project owner to create many invites at once', done => {
Async.series(
[
cb => expectProjectAccess(this.sendingUser, this.projectId, cb),
cb =>
expectInviteListCount(this.sendingUser, this.projectId, 0, cb),
// create first invite
cb => {
return createInvite(
createInvite(
this.sendingUser,
this.projectId,
this.email,
@ -543,7 +425,7 @@ describe('ProjectInviteTests', function() {
return cb(err)
}
this.inviteOne = invite
return cb()
cb()
}
)
},
@ -551,7 +433,7 @@ describe('ProjectInviteTests', function() {
expectInviteListCount(this.sendingUser, this.projectId, 1, cb),
// and a second
cb => {
return createInvite(
createInvite(
this.sendingUser,
this.projectId,
this.email,
@ -560,7 +442,7 @@ describe('ProjectInviteTests', function() {
return cb(err)
}
this.inviteTwo = invite
return cb()
cb()
}
)
},
@ -600,64 +482,31 @@ describe('ProjectInviteTests', function() {
})
})
describe('clicking the invite link', function() {
beforeEach(function(done) {
this.projectId = null
this.fakeProject = null
return done()
describe('clicking the invite link', () => {
beforeEach(done => {
createProjectAndInvite(
this.sendingUser,
this.projectName,
this.email,
(err, project, invite, link) => {
expect(err).not.to.exist
this.projectId = project._id
this.fakeProject = project
this.invite = invite
this.link = link
done()
}
)
})
describe('user is logged in already', function() {
beforeEach(function(done) {
return Async.series(
[
cb => {
return createProjectAndInvite(
this.sendingUser,
this.projectName,
this.email,
(err, project, invite, link) => {
this.projectId = project._id
this.fakeProject = project
this.invite = invite
this.link = link
return cb()
}
)
},
cb => {
return this.user.login(err => {
if (err) {
throw err
}
return cb()
})
}
],
done
)
describe('user is logged in already', () => {
beforeEach(done => {
this.user.login(done)
})
afterEach(function(done) {
return Async.series(
[
cb => this.sendingUser.deleteProject(this.projectId, cb),
cb => this.sendingUser.deleteProject(this.projectId, cb),
cb =>
revokeInvite(
this.sendingUser,
this.projectId,
this.invite._id,
cb
)
],
done
)
})
describe('user is already a member of the project', function() {
beforeEach(function(done) {
return Async.series(
describe('user is already a member of the project', () => {
beforeEach(done => {
Async.series(
[
cb => expectInvitePage(this.user, this.link, cb),
cb => expectAcceptInviteAndRedirect(this.user, this.invite, cb),
@ -667,9 +516,9 @@ describe('ProjectInviteTests', function() {
)
})
describe('when user clicks on the invite a second time', function() {
it('should just redirect to the project page', function(done) {
return Async.series(
describe('when user clicks on the invite a second time', () => {
it('should just redirect to the project page', done => {
Async.series(
[
cb => expectProjectAccess(this.user, this.invite.projectId, cb),
cb =>
@ -686,11 +535,11 @@ describe('ProjectInviteTests', function() {
})
describe('when the user recieves another invite to the same project', () =>
it('should redirect to the project page', function(done) {
return Async.series(
it('should redirect to the project page', done => {
Async.series(
[
cb => {
return createInvite(
createInvite(
this.sendingUser,
this.projectId,
this.email,
@ -703,7 +552,7 @@ describe('ProjectInviteTests', function() {
this.fakeProject,
invite
)
return cb()
cb()
}
)
},
@ -730,9 +579,9 @@ describe('ProjectInviteTests', function() {
})
})
describe('user is not a member of the project', function() {
it('should not grant access if the user does not accept the invite', function(done) {
return Async.series(
describe('user is not a member of the project', () => {
it('should not grant access if the user does not accept the invite', done => {
Async.series(
[
cb => expectInvitePage(this.user, this.link, cb),
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb)
@ -741,15 +590,15 @@ describe('ProjectInviteTests', function() {
)
})
it('should render the invalid-invite page if the token is invalid', function(done) {
return Async.series(
it('should render the invalid-invite page if the token is invalid', done => {
Async.series(
[
cb => {
const link = this.link.replace(
this.invite.token,
'not_a_real_token'
)
return expectInvalidInvitePage(this.user, link, cb)
expectInvalidInvitePage(this.user, link, cb)
},
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb),
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb)
@ -758,8 +607,8 @@ describe('ProjectInviteTests', function() {
)
})
it('should allow the user to accept the invite and access the project', function(done) {
return Async.series(
it('should allow the user to accept the invite and access the project', done => {
Async.series(
[
cb => expectInvitePage(this.user, this.link, cb),
cb => expectAcceptInviteAndRedirect(this.user, this.invite, cb),
@ -771,60 +620,14 @@ describe('ProjectInviteTests', function() {
})
})
describe('user is not logged in initially', function() {
before(function(done) {
return this.user.logout(done)
})
beforeEach(function(done) {
return Async.series(
[
cb => {
return createProjectAndInvite(
this.sendingUser,
this.projectName,
this.email,
(err, project, invite, link) => {
this.projectId = project._id
this.fakeProject = project
this.invite = invite
this.link = link
return cb()
}
)
}
],
done
)
})
afterEach(function(done) {
return Async.series(
[
cb => this.sendingUser.deleteProject(this.projectId, cb),
cb => this.sendingUser.deleteProject(this.projectId, cb),
cb =>
revokeInvite(
this.sendingUser,
this.projectId,
this.invite._id,
cb
)
],
done
)
})
describe('registration prompt workflow with valid token', function() {
it('should redirect to the register page', function(done) {
return Async.series(
[cb => expectInviteRedirectToRegister(this.user, this.link, cb)],
done
)
describe('user is not logged in initially', () => {
describe('registration prompt workflow with valid token', () => {
it('should redirect to the register page', done => {
expectInviteRedirectToRegister(this.user, this.link, done)
})
it('should allow user to accept the invite if the user registers a new account', function(done) {
return Async.series(
it('should allow user to accept the invite if the user registers a new account', done => {
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
cb =>
@ -843,13 +646,9 @@ describe('ProjectInviteTests', function() {
})
})
describe('registration prompt workflow with non-valid token', function() {
before(function(done) {
return this.user.logout(done)
})
it('should redirect to the register page', function(done) {
return Async.series(
describe('registration prompt workflow with non-valid token', () => {
it('should redirect to the register page', done => {
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb)
@ -858,12 +657,12 @@ describe('ProjectInviteTests', function() {
)
})
it('should display invalid-invite if the user registers a new account', function(done) {
it('should display invalid-invite if the user registers a new account', done => {
const badLink = this.link.replace(
this.invite.token,
'not_a_real_token'
)
return Async.series(
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, badLink, cb),
cb =>
@ -881,13 +680,9 @@ describe('ProjectInviteTests', function() {
})
})
describe('login workflow with valid token', function() {
before(function(done) {
return this.user.logout(done)
})
it('should redirect to the register page', function(done) {
return Async.series(
describe('login workflow with valid token', () => {
it('should redirect to the register page', done => {
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb)
@ -896,8 +691,8 @@ describe('ProjectInviteTests', function() {
)
})
it('should allow the user to login to view the invite', function(done) {
return Async.series(
it('should allow the user to login to view the invite', done => {
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
cb => expectLoginPage(this.user, cb),
@ -909,9 +704,12 @@ describe('ProjectInviteTests', function() {
)
})
it('should allow user to accept the invite if the user registers a new account', function(done) {
return Async.series(
it('should allow user to accept the invite if the user logs in', done => {
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
cb => expectLoginPage(this.user, cb),
cb => expectLoginRedirectToInvite(this.user, this.link, cb),
cb => expectInvitePage(this.user, this.link, cb),
cb => expectAcceptInviteAndRedirect(this.user, this.invite, cb),
cb => expectProjectAccess(this.user, this.invite.projectId, cb)
@ -921,13 +719,9 @@ describe('ProjectInviteTests', function() {
})
})
describe('login workflow with non-valid token', function() {
before(function(done) {
return this.user.logout(done)
})
it('should redirect to the register page', function(done) {
return Async.series(
describe('login workflow with non-valid token', () => {
it('should redirect to the register page', done => {
Async.series(
[
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb)
@ -936,12 +730,12 @@ describe('ProjectInviteTests', function() {
)
})
it('should show the invalid-invite page once the user has logged in', function(done) {
it('should show the invalid-invite page once the user has logged in', done => {
const badLink = this.link.replace(
this.invite.token,
'not_a_real_token'
)
return Async.series(
Async.series(
[
cb => {
return expectInviteRedirectToRegister(this.user, badLink, cb)