-
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 #6453 from NMDSdevopsServiceAdm/feat/1572-forgot-u…
…sername-page-first-half Feat/1572 forgot username page first half
- Loading branch information
Showing
26 changed files
with
806 additions
and
12 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,55 @@ | ||
const { isEmpty } = require('lodash'); | ||
const { sanitisePostcode } = require('../../utils/postcodeSanitizer'); | ||
const models = require('../../models/index'); | ||
|
||
const findUserAccount = async (req, res) => { | ||
try { | ||
if (requestIsInvalid(req)) { | ||
return res.status(400).send('Invalid request'); | ||
} | ||
|
||
const { name, workplaceIdOrPostcode, email } = req.body; | ||
let userFound = null; | ||
|
||
const postcode = sanitisePostcode(workplaceIdOrPostcode); | ||
if (postcode) { | ||
userFound = await models.user.findByRelevantInfo({ name, postcode, email }); | ||
} | ||
|
||
userFound = | ||
userFound ?? (await models.user.findByRelevantInfo({ name, workplaceId: workplaceIdOrPostcode, email })); | ||
|
||
if (userFound) { | ||
return sendSuccessResponse(res, userFound); | ||
} | ||
|
||
return sendNotFoundResponse(res); | ||
} catch (err) { | ||
console.error('registration POST findUserAccount - failed', err); | ||
return res.status(500).send('Internal server error'); | ||
} | ||
}; | ||
|
||
const requestIsInvalid = (req) => { | ||
if (!req.body) { | ||
return true; | ||
} | ||
const { name, workplaceIdOrPostcode, email } = req.body; | ||
|
||
return [name, workplaceIdOrPostcode, email].some((field) => isEmpty(field)); | ||
}; | ||
|
||
const sendSuccessResponse = (res, userFound) => { | ||
const { uid, SecurityQuestionValue } = userFound; | ||
return res.status(200).json({ | ||
accountFound: true, | ||
accountUid: uid, | ||
securityQuestion: SecurityQuestionValue, | ||
}); | ||
}; | ||
|
||
const sendNotFoundResponse = (res) => { | ||
return res.status(200).json({ accountFound: false, remainingAttempts: 4 }); | ||
}; | ||
|
||
module.exports = { findUserAccount }; |
151 changes: 151 additions & 0 deletions
151
backend/server/test/unit/routes/registration/findUserAccount.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,151 @@ | ||
const chai = require('chai'); | ||
const sinon = require('sinon'); | ||
const expect = chai.expect; | ||
const httpMocks = require('node-mocks-http'); | ||
|
||
const { findUserAccount } = require('../../../../routes/registration/findUserAccount'); | ||
const models = require('../../../../models/index'); | ||
|
||
describe('backend/server/routes/registration/findUserAccount', () => { | ||
const mockRequestBody = { name: 'Test User', workplaceIdOrPostcode: 'A1234567', email: '[email protected]' }; | ||
|
||
const buildRequest = (body) => { | ||
const request = { | ||
method: 'POST', | ||
url: '/api/registration/findUserAccount', | ||
body, | ||
}; | ||
return httpMocks.createRequest(request); | ||
}; | ||
|
||
let stubFindUser; | ||
beforeEach(() => { | ||
stubFindUser = sinon.stub(models.user, 'findByRelevantInfo').callsFake(({ workplaceId, postcode }) => { | ||
if (workplaceId === 'A1234567' || postcode === 'LS1 2RP') { | ||
return { uid: 'mock-uid', SecurityQuestionValue: 'What is your favourite colour?' }; | ||
} | ||
return null; | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
sinon.restore(); | ||
}); | ||
|
||
it('should respond with 200 and accountFound: true if user account is found', async () => { | ||
const req = buildRequest(mockRequestBody); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUserAccount(req, res); | ||
|
||
expect(res.statusCode).to.equal(200); | ||
expect(res._getJSONData()).to.deep.equal({ | ||
accountFound: true, | ||
accountUid: 'mock-uid', | ||
securityQuestion: 'What is your favourite colour?', | ||
}); | ||
|
||
expect(stubFindUser).to.have.been.calledWith({ | ||
name: 'Test User', | ||
workplaceId: 'A1234567', | ||
email: '[email protected]', | ||
}); | ||
}); | ||
|
||
it('should find user with postcode if request body contains a postcode', async () => { | ||
const req = buildRequest({ ...mockRequestBody, workplaceIdOrPostcode: 'LS1 2RP' }); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUserAccount(req, res); | ||
|
||
expect(res.statusCode).to.equal(200); | ||
expect(res._getJSONData()).to.deep.equal({ | ||
accountFound: true, | ||
accountUid: 'mock-uid', | ||
securityQuestion: 'What is your favourite colour?', | ||
}); | ||
|
||
expect(stubFindUser).to.have.been.calledWith({ | ||
name: 'Test User', | ||
postcode: 'LS1 2RP', | ||
email: '[email protected]', | ||
}); | ||
}); | ||
|
||
it('should try to search with both postcode and workplace ID if incoming param is not distinguishable', async () => { | ||
const req = buildRequest({ ...mockRequestBody, workplaceIdOrPostcode: 'AB101AB' }); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUserAccount(req, res); | ||
|
||
expect(stubFindUser).to.have.been.calledWith({ | ||
name: 'Test User', | ||
postcode: 'AB10 1AB', | ||
email: '[email protected]', | ||
}); | ||
|
||
expect(stubFindUser).to.have.been.calledWith({ | ||
name: 'Test User', | ||
workplaceId: 'AB101AB', | ||
email: '[email protected]', | ||
}); | ||
}); | ||
|
||
it('should respond with 200 and accountFound: false if user account was not found', async () => { | ||
const req = buildRequest({ ...mockRequestBody, workplaceIdOrPostcode: 'non-exist-workplace-id' }); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUserAccount(req, res); | ||
|
||
expect(res.statusCode).to.equal(200); | ||
expect(res._getJSONData()).to.deep.equal({ | ||
accountFound: 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/findUserAccount', | ||
}); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUserAccount(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 findUserAccount(req, res); | ||
expect(res.statusCode).to.equal(400); | ||
}); | ||
|
||
Object.keys(mockRequestBody).forEach((field) => { | ||
it(`should respond with 400 error if ${field} is missing from request body`, async () => { | ||
const body = { ...mockRequestBody }; | ||
delete body[field]; | ||
|
||
const req = buildRequest(body); | ||
const res = httpMocks.createResponse(); | ||
|
||
await findUserAccount(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 | ||
stubFindUser.rejects(new Error('mock database error')); | ||
|
||
await findUserAccount(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
35 changes: 35 additions & 0 deletions
35
frontend/src/app/core/services/find-username.service.spec.ts
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,35 @@ | ||
import { environment } from 'src/environments/environment'; | ||
|
||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; | ||
import { TestBed } from '@angular/core/testing'; | ||
|
||
import { FindUsernameService } from './find-username.service'; | ||
|
||
describe('FindUsernameService', () => { | ||
let service: FindUsernameService; | ||
let http: HttpTestingController; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [HttpClientTestingModule], | ||
}); | ||
service = TestBed.inject(FindUsernameService); | ||
http = TestBed.inject(HttpTestingController); | ||
}); | ||
|
||
it('should be created', () => { | ||
expect(service).toBeTruthy(); | ||
}); | ||
|
||
describe('findUserAccount', () => { | ||
it('should make a POST request to /registration/findUserAccount endpoint with the given search params', async () => { | ||
const mockParams = { name: 'Test user', workplaceIdOrPostcode: 'A1234567', email: '[email protected]' }; | ||
|
||
service.findUserAccount(mockParams).subscribe(); | ||
const req = http.expectOne(`${environment.appRunnerEndpoint}/api/registration/findUserAccount`); | ||
|
||
expect(req.request.method).toBe('POST'); | ||
expect(req.request.body).toEqual(mockParams); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.