-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6456 from NMDSdevopsServiceAdm/feat/1568-forgot-u…
…sername-page-second-half Feat/1568 forgot username page second half
- Loading branch information
Showing
14 changed files
with
655 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
const { isEmpty } = require('lodash'); | ||
const models = require('../../models/index'); | ||
|
||
const findUsername = async (req, res) => { | ||
try { | ||
if (requestIsInvalid(req)) { | ||
return res.status(400).send('Invalid request'); | ||
} | ||
|
||
const { uid, securityQuestionAnswer } = req.body; | ||
const userFound = await models.user.getUsernameWithSecurityQuestionAnswer({ uid, securityQuestionAnswer }); | ||
|
||
if (!userFound) { | ||
return sendFailedResponse(res); | ||
} | ||
|
||
return sendSuccessResponse(res, userFound); | ||
} catch (err) { | ||
console.error('registration POST findUsername - failed', err); | ||
return res.status(500).send('Internal server error'); | ||
} | ||
}; | ||
|
||
const requestIsInvalid = (req) => { | ||
if (!req.body) { | ||
return true; | ||
} | ||
const { securityQuestionAnswer, uid } = req.body; | ||
|
||
return [securityQuestionAnswer, uid].some((field) => isEmpty(field)); | ||
}; | ||
|
||
const sendSuccessResponse = (res, userFound) => { | ||
const { username } = userFound; | ||
return res.status(200).json({ | ||
answerCorrect: true, | ||
username, | ||
}); | ||
}; | ||
|
||
const sendFailedResponse = (res) => { | ||
return res.status(401).json({ answerCorrect: false, remainingAttempts: 4 }); | ||
}; | ||
|
||
module.exports = { findUsername }; |
123 changes: 123 additions & 0 deletions
123
backend/server/test/unit/routes/registration/findUsername.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
const chai = require('chai'); | ||
const sinon = require('sinon'); | ||
const expect = chai.expect; | ||
const httpMocks = require('node-mocks-http'); | ||
|
||
const { findUsername } = require('../../../../routes/registration/findUsername'); | ||
const models = require('../../../../models/index'); | ||
|
||
describe('backend/server/routes/registration/findUsername', () => { | ||
const mockRequestBody = { | ||
uid: 'mock-uid', | ||
securityQuestionAnswer: '42', | ||
}; | ||
|
||
const buildRequest = (body) => { | ||
const request = { | ||
method: 'POST', | ||
url: '/api/registration/findUsername', | ||
body, | ||
}; | ||
return httpMocks.createRequest(request); | ||
}; | ||
|
||
let stubGetUsername; | ||
|
||
beforeEach(() => { | ||
stubGetUsername = sinon | ||
.stub(models.user, 'getUsernameWithSecurityQuestionAnswer') | ||
.callsFake(({ securityQuestionAnswer }) => { | ||
if (securityQuestionAnswer === '42') { | ||
return { username: 'test-user' }; | ||
} | ||
return null; | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
sinon.restore(); | ||
}); | ||
|
||
it('should respond with 200 and username if securityQuestionAnswer is correct', async () => { | ||
const req = buildRequest(mockRequestBody); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(200); | ||
expect(res._getJSONData()).to.deep.equal({ | ||
answerCorrect: true, | ||
username: 'test-user', | ||
}); | ||
|
||
expect(stubGetUsername).to.have.been.calledWith({ | ||
uid: 'mock-uid', | ||
securityQuestionAnswer: '42', | ||
}); | ||
}); | ||
|
||
it('should respond with 401 Unauthorised and number of remainingAttempts if securityQuestionAnswer is incorrect', async () => { | ||
const req = buildRequest({ uid: 'mock-uid', securityQuestionAnswer: 'some random thing' }); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(401); | ||
expect(res._getJSONData()).to.deep.equal({ | ||
answerCorrect: false, | ||
remainingAttempts: 4, | ||
}); | ||
}); | ||
|
||
it('should respond with 400 error if request does not have a body', async () => { | ||
const req = httpMocks.createRequest({ | ||
method: 'POST', | ||
url: '/api/registration/findUsername', | ||
}); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(400); | ||
}); | ||
|
||
it('should respond with 400 error if request body is empty', async () => { | ||
const req = buildRequest({}); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(400); | ||
}); | ||
|
||
it('should respond with 400 error if securityQuestionAnswer is missing', async () => { | ||
const req = buildRequest({ uid: mockRequestBody.uid }); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(400); | ||
}); | ||
|
||
it('should respond with 400 error if uid is missing', async () => { | ||
const req = buildRequest({ securityQuestionAnswer: mockRequestBody.securityQuestionAnswer }); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(400); | ||
}); | ||
|
||
it('should respond with 500 Internal server error if an error occur when finding user', async () => { | ||
const req = buildRequest(mockRequestBody); | ||
const res = httpMocks.createResponse(); | ||
|
||
sinon.stub(console, 'error'); // suppress noisy logging | ||
stubGetUsername.rejects(new Error('mock database error')); | ||
|
||
await findUsername(req, res); | ||
|
||
expect(res.statusCode).to.equal(500); | ||
expect(res._getData()).to.equal('Internal server error'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.