import { expect } from 'chai'; import * as sinon from 'sinon'; import * as proxyquire from 'proxyquire'; import { TestConfiguration } from '../../src/configuration'; import { HttpRequest } from '../../src/types/request'; const sandbox = sinon.createSandbox(); describe('getToken', () => { const mockSession = 'test-session'; const mockSessionSecure = 'test-session-secure'; let auth: any; let mockAuthorisation: any; let authTokenStub: any; let fetchStub: any; beforeEach(() => { authTokenStub = sandbox.stub(); fetchStub = sandbox.stub(); mockAuthorisation = proxyquire('../../src/authorisation', { './request/authorisation-token': { authorisationTokenRequest: authTokenStub } }).Authorisation; const config = new TestConfiguration({ authorisationApiClientId: 'secret', loginApiKey: 'secret', userCredApiKey: 'secret', originSystemId: 'n-membership-sdk test', }); auth = new mockAuthorisation(config, { fetchOverride: fetchStub }); sandbox.stub(auth, 'requestPost').resolves({}); }); afterEach(() => { sandbox.restore(); }); describe('Authorisation', () => { it('passes through to the authorisationTokenRequest function', () => { auth.getToken(mockSession); const authTokenParams = authTokenStub.getCall(0).args[0]; expect(authTokenParams).to.have.property('url'); expect(authTokenParams.url).to.equal('https://api-t.ft.com/authorize'); expect(authTokenParams).to.have.property('sessionToken', mockSession); }); it('throws an error when clientId is missing from the config', async () => { try { await new mockAuthorisation(new TestConfiguration()); expect.fail('Should have thrown the error!'); } catch (error) { } }); }); describe('login', () => { beforeEach(() => { auth.requestPost.resolves({ success: true, status: 'SUCCESS', session: mockSession, secureSession: mockSessionSecure, userId: '11111111-1111-1111-1111-111111111111' }); }); it('should pass correct parameters to requestPost', async () => { const mockProfileData = { email: 'test-email', password: 'test-password', rememberMe: true }; await auth.login('test-email', 'test-password', true); const postParams: HttpRequest = auth.requestPost.getCall(0).args[0]; // Path checks expect(postParams).to.have.property('url'); expect(postParams.url).to.equal('https://api-t.ft.com/idm/v1/login'); // Body checks const expectedBody = { ...mockProfileData, context: {}, skipRecaptcha: true }; expect(postParams).to.have.property('body'); expect(postParams.body).to.deep.equal(expectedBody); }); it('returns an array of session cookie data', async () => { // take a second off for good measure. const expireAfter = new Date(Date.now() + auth.SESSION_COOKIE_EXPIRY - 1000); const cookies = await auth.login('test-email', 'test-password', true); const testCookie = (cookie: any, key: string, token: string) => { expect(cookie.key).to.equal(key); expect(cookie.token).to.equal(token); expect(cookie.options.path).to.equal('/'); expect(cookie.options.domain).to.equal('.ft.com'); expect(cookie.options.expires.getTime()).to.be.greaterThan(expireAfter.getTime()); }; expect(cookies.length).to.equal(2); testCookie(cookies[0], 'FTSession', mockSession); testCookie(cookies[1], 'FTSession_s', mockSessionSecure); expect(cookies[1].options.secure).to.be.true; }); it('defaults rememberMe to false', async () => { await auth.login('test-email', 'test-password'); const postParams = auth.requestPost.getCall(0).args[0]; expect(postParams.body.rememberMe).to.equal(false); }); context('when an error is thrown', () => { const errorResponse = new Error('Test failure'); beforeEach(() => { auth.requestPost.rejects(errorResponse); }); it('it throws the same error', async () => { try { await auth.login('test-email', 'test-password', true); expect.fail('Should have thrown the error!'); } catch (error) { expect(error).to.deep.equal(errorResponse); } }); }); context('when non-success status code is returned', () => { const errorResponse = { success: false, status: 'FAILED_CRED_NOT_FOUND' }; beforeEach(() => { auth.requestPost.resolves(errorResponse); }); it('it throws the same error', async () => { const expectedError = { message: 'auth failed', data: errorResponse }; try { await auth.login('test-email', 'test-password', true); expect.fail('Should have thrown the error!'); } catch (error) { expect(error.message).to.equal(expectedError.message); expect(error.data).to.deep.equal(expectedError.data); } }); }); }); describe('changePassword', () => { let result: boolean; let postParams: HttpRequest; beforeEach(() => { auth.requestPost.resolves({ ok: true }); }); describe('reasonForChange is passwordless-signup', () => { beforeEach(async () => { result = await auth.changePassword('test-id', 'passwordless-signup'); postParams = auth.requestPost.getCall(0).args[0]; }); it('should pass the correct URL to requestPost', () => { const url = `${auth.membershipApi}/idm/v1/users/test-id/credentials/change-password`; expect(postParams).to.have.property('url'); expect(postParams.url).to.equal(url); }); it('should pass the correct body to requestPost', () => { expect(postParams).to.have.property('body'); expect(postParams.body?.reasonForChange).to.equal('passwordless-signup'); }); it('returns whether the attempt was successful', () => { expect(result).to.equal(true); }); }); context('reasonForChange is reset-password', () => { beforeEach(async () => { result = await auth.changePassword('test-id', 'reset-password', 'test-new', 'test-old', 'test-token'); postParams = auth.requestPost.getCall(0).args[0]; }); it('should pass reasonForChange to requestPost', () => { expect(postParams.body?.reasonForChange).to.equal('reset-password'); }); it('should pass new password to requestPost', () => { expect(postParams.body?.password).to.equal('test-new'); }); it('should pass old password to requestPost', () => { expect(postParams.body?.oldPassword).to.equal('test-old'); }); it('should pass token to requestPost', () => { expect(postParams.body?.token).to.equal('test-token'); }); it('returns whether the attempt was successful', () => { expect(result).to.equal(true); }); }); context('when an error is thrown', () => { const errorResponse = new Error('Test failure'); beforeEach(() => { auth.requestPost.rejects(errorResponse); }); it('it throws the same error', async () => { try { await auth.changePassword('test-id', 'reset-password', 'test-new', 'test-old', 'test-token'); expect.fail('Should have thrown the error!'); } catch (error) { expect(error).to.deep.equal(errorResponse); } }); }); }); });