diff --git a/src/components/account-intervention/tests/account-intervention-service.test.ts b/src/components/account-intervention/tests/account-intervention-service.test.ts new file mode 100644 index 0000000000..fd4ddb3130 --- /dev/null +++ b/src/components/account-intervention/tests/account-intervention-service.test.ts @@ -0,0 +1,62 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { AccountInterventionsInterface } from "../types"; +import { accountInterventionService } from "../account-intervention-service"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../test/helpers/service-test-helper"; +import { API_ENDPOINTS } from "../../../app.constants"; +import { Http } from "../../../utils/http"; + +describe("account interventions service", () => { + const httpInstance = new Http(); + const service: AccountInterventionsInterface = + accountInterventionService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to check a user's account interventions status", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: 200, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { sessionId, clientSessionId, email, ip, diPersistentSessionId } = + commonVariables; + + const result = await service.accountInterventionStatus( + sessionId, + email, + ip, + clientSessionId, + diPersistentSessionId + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.ACCOUNT_INTERVENTIONS, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { email: commonVariables.email }, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/check-reauth-users/tests/check-reauth-user-service.test.ts b/src/components/check-reauth-users/tests/check-reauth-user-service.test.ts index b9ffa846ab..1ce14e33c3 100644 --- a/src/components/check-reauth-users/tests/check-reauth-user-service.test.ts +++ b/src/components/check-reauth-users/tests/check-reauth-user-service.test.ts @@ -1,22 +1,66 @@ -import { expect } from "chai"; import { describe } from "mocha"; - -import { supportReauthentication } from "../../../config"; +import { Http } from "../../../utils/http"; +import { sinon } from "../../../../test/utils/test-utils"; +import { API_ENDPOINTS } from "../../../app.constants"; +import { SinonStub } from "sinon"; +import { checkReauthUsersService } from "../check-reauth-users-service"; +import { CheckReauthServiceInterface } from "../types"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../test/helpers/service-test-helper"; describe("re-authentication service", () => { - describe("with auth re-authentication feature flag on", () => { - it("should return true", async () => { - process.env.SUPPORT_REAUTHENTICATION = "1"; + const httpInstance = new Http(); + const service: CheckReauthServiceInterface = + checkReauthUsersService(httpInstance); + const SUBJECT = "123"; + let postStub: SinonStub; - expect(supportReauthentication()).to.be.true; - }); + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); }); - describe("with auth re-authentication feature flag off", () => { - it("should return false", async () => { - process.env.SUPPORT_REAUTHENTICATION = "0"; + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); - expect(supportReauthentication()).to.be.false; + it("successfully calls the API to check a reauth user", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: 200, + statusText: "OK", }); + postStub.resolves(axiosResponse); + const { sessionId, email, ip, clientSessionId, diPersistentSessionId } = + commonVariables; + + const result = await service.checkReauthUsers( + sessionId, + email, + SUBJECT, + ip, + clientSessionId, + diPersistentSessionId + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.CHECK_REAUTH_USER, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { email: commonVariables.email, rpPairwiseId: SUBJECT }, + validateStatus: true, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); }); }); diff --git a/src/components/common/account-recovery/tests/account-recovery-service.test.ts b/src/components/common/account-recovery/tests/account-recovery-service.test.ts new file mode 100644 index 0000000000..9db45b8b57 --- /dev/null +++ b/src/components/common/account-recovery/tests/account-recovery-service.test.ts @@ -0,0 +1,62 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../../utils/http"; +import { AccountRecoveryInterface } from "../types"; +import { accountRecoveryService } from "../account-recovery-service"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../../test/helpers/service-test-helper"; +import { API_ENDPOINTS } from "../../../../app.constants"; + +describe("account recovery service", () => { + const httpInstance = new Http(); + const service: AccountRecoveryInterface = + accountRecoveryService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to perform an account recovery request", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: 200, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { sessionId, clientSessionId, email, ip, diPersistentSessionId } = + commonVariables; + + const result = await service.accountRecovery( + sessionId, + clientSessionId, + email, + ip, + diPersistentSessionId + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.ACCOUNT_RECOVERY, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { email: commonVariables.email }, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/common/mfa/tests/mfa-service.test.ts b/src/components/common/mfa/tests/mfa-service.test.ts new file mode 100644 index 0000000000..ccb86b6020 --- /dev/null +++ b/src/components/common/mfa/tests/mfa-service.test.ts @@ -0,0 +1,74 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../../utils/http"; +import { MfaServiceInterface } from "../types"; +import { mfaService } from "../mfa-service"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../../test/helpers/service-test-helper"; +import { + API_ENDPOINTS, + HTTP_STATUS_CODES, + JOURNEY_TYPE, +} from "../../../../app.constants"; + +describe("mfa service", () => { + const httpInstance = new Http(); + const service: MfaServiceInterface = mfaService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to make a request to reset a password ", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.NO_CONTENT, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { email, sessionId, clientSessionId, ip, diPersistentSessionId } = + commonVariables; + const userLanguage = "cy"; + const journeyType = JOURNEY_TYPE.SIGN_IN; + const isResendCodeRequest = true; + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.MFA, + expectedHeaders: { + ...expectedHeadersFromCommonVarsWithoutSecurityHeaders, + "User-Language": userLanguage, + }, + expectedBody: { email, isResendCodeRequest, journeyType }, + }; + + const result = await service.sendMfaCode( + sessionId, + clientSessionId, + email, + ip, + diPersistentSessionId, + isResendCodeRequest, + userLanguage, + journeyType + ); + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/common/send-notification/tests/send-notification-service.test.ts b/src/components/common/send-notification/tests/send-notification-service.test.ts new file mode 100644 index 0000000000..938750a61e --- /dev/null +++ b/src/components/common/send-notification/tests/send-notification-service.test.ts @@ -0,0 +1,109 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../../utils/http"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../../test/helpers/service-test-helper"; +import { API_ENDPOINTS, NOTIFICATION_TYPE } from "../../../../app.constants"; +import { SendNotificationServiceInterface } from "../types"; +import { sendNotificationService } from "../send-notification-service"; +import { JOURNEY_TYPE } from "../../constants"; + +describe("send notification service", () => { + let postStub: SinonStub; + let service: SendNotificationServiceInterface; + const axiosResponse = Promise.resolve({ + data: {}, + status: 200, + statusText: "OK", + }); + const { sessionId, clientSessionId, email, ip, diPersistentSessionId } = + commonVariables; + const notificationType = NOTIFICATION_TYPE.VERIFY_EMAIL; + const userLanguage = "cy"; + const expectedHeaders = { + ...expectedHeadersFromCommonVarsWithoutSecurityHeaders, + "User-Language": userLanguage, + }; + + beforeEach(() => { + const httpInstance = new Http(); + service = sendNotificationService(httpInstance); + postStub = sinon.stub(httpInstance.client, "post"); + setupApiKeyAndBaseUrlEnvVars(); + postStub.resolves(axiosResponse); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to send a notification", async () => { + const result = await service.sendNotification( + sessionId, + clientSessionId, + email, + notificationType, + ip, + diPersistentSessionId, + userLanguage + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.SEND_NOTIFICATION, + expectedHeaders, + expectedBody: { email, notificationType }, + validateStatus: true, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); + + it("adds the additional details to the payload when these are included", async () => { + const journeyType = JOURNEY_TYPE.CREATE_ACCOUNT; + const phoneNumber = "123456"; + const requestNewCode = true; + const result = await service.sendNotification( + sessionId, + clientSessionId, + email, + notificationType, + ip, + diPersistentSessionId, + userLanguage, + journeyType, + phoneNumber, + requestNewCode + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.SEND_NOTIFICATION, + expectedHeaders, + expectedBody: { + email, + notificationType, + journeyType, + phoneNumber, + requestNewCode, + }, + validateStatus: true, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/common/update-profile/test/update-profile-service.test.ts b/src/components/common/update-profile/test/update-profile-service.test.ts new file mode 100644 index 0000000000..8ce3c3a762 --- /dev/null +++ b/src/components/common/update-profile/test/update-profile-service.test.ts @@ -0,0 +1,65 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../../utils/http"; +import { UpdateProfileServiceInterface, UpdateType } from "../types"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../../test/helpers/service-test-helper"; +import { API_ENDPOINTS, HTTP_STATUS_CODES } from "../../../../app.constants"; +import { updateProfileService } from "../update-profile-service"; + +describe("update profile service", () => { + const httpInstance = new Http(); + const service: UpdateProfileServiceInterface = + updateProfileService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to update a profile", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.NO_CONTENT, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { sessionId, clientSessionId, email, ip, diPersistentSessionId } = + commonVariables; + const profileInformation = true; + const updateProfileType = UpdateType.CAPTURE_CONSENT; + + const result = await service.updateProfile( + sessionId, + clientSessionId, + email, + { profileInformation, updateProfileType }, + ip, + diPersistentSessionId + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.UPDATE_PROFILE, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { email, profileInformation, updateProfileType }, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/common/verify-code/tests/verify-code-service.test.ts b/src/components/common/verify-code/tests/verify-code-service.test.ts new file mode 100644 index 0000000000..26ffe04131 --- /dev/null +++ b/src/components/common/verify-code/tests/verify-code-service.test.ts @@ -0,0 +1,71 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../../utils/http"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../../test/helpers/service-test-helper"; +import { + API_ENDPOINTS, + HTTP_STATUS_CODES, + JOURNEY_TYPE, + NOTIFICATION_TYPE, +} from "../../../../app.constants"; +import { VerifyCodeInterface } from "../types"; +import { codeService } from "../verify-code-service"; + +describe("verify code service", () => { + const httpInstance = new Http(); + const service: VerifyCodeInterface = codeService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to verify a code", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.NO_CONTENT, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { sessionId, clientSessionId, ip, diPersistentSessionId } = + commonVariables; + const code = "1234"; + const notificationType = NOTIFICATION_TYPE.VERIFY_EMAIL; + const journeyType = JOURNEY_TYPE.SIGN_IN; + + const result = await service.verifyCode( + sessionId, + code, + notificationType, + clientSessionId, + ip, + diPersistentSessionId, + journeyType + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.VERIFY_CODE, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { code, notificationType, journeyType }, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/common/verify-mfa-code/test/verify-mfa-code-service.test.ts b/src/components/common/verify-mfa-code/test/verify-mfa-code-service.test.ts new file mode 100644 index 0000000000..8362ccd5ea --- /dev/null +++ b/src/components/common/verify-mfa-code/test/verify-mfa-code-service.test.ts @@ -0,0 +1,73 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../../utils/http"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../../test/helpers/service-test-helper"; +import { + API_ENDPOINTS, + HTTP_STATUS_CODES, + JOURNEY_TYPE, + MFA_METHOD_TYPE, +} from "../../../../app.constants"; +import { VerifyMfaCodeInterface } from "../../../enter-authenticator-app-code/types"; +import { verifyMfaCodeService } from "../verify-mfa-code-service"; + +describe("verify mfa code service", () => { + const httpInstance = new Http(); + const service: VerifyMfaCodeInterface = verifyMfaCodeService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to verify an mfa code", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.NO_CONTENT, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { sessionId, clientSessionId, ip, diPersistentSessionId } = + commonVariables; + const code = "1234"; + const journeyType = JOURNEY_TYPE.SIGN_IN; + const mfaMethodType = MFA_METHOD_TYPE.SMS; + const profileInformation = "some profile information"; //TODO check for realistic value + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.VERIFY_MFA_CODE, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { mfaMethodType, code, journeyType, profileInformation }, + }; + + const result = await service.verifyMfaCode( + mfaMethodType, + code, + sessionId, + clientSessionId, + ip, + diPersistentSessionId, + journeyType, + profileInformation + ); + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/prove-identity-callback/tests/prove-identity-callback-service.test.ts b/src/components/prove-identity-callback/tests/prove-identity-callback-service.test.ts new file mode 100644 index 0000000000..68e5b43992 --- /dev/null +++ b/src/components/prove-identity-callback/tests/prove-identity-callback-service.test.ts @@ -0,0 +1,62 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../test/helpers/service-test-helper"; +import { Http } from "../../../utils/http"; +import { ProveIdentityCallbackServiceInterface } from "../types"; +import { proveIdentityCallbackService } from "../prove-identity-callback-service"; +import { API_ENDPOINTS, HTTP_STATUS_CODES } from "../../../app.constants"; + +describe("prove identity callback service", () => { + const httpInstance = new Http(); + const service: ProveIdentityCallbackServiceInterface = + proveIdentityCallbackService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to make a request to reset a password ", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.OK, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { email, sessionId, clientSessionId, ip, diPersistentSessionId } = + commonVariables; + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.IPV_PROCESSING_IDENTITY, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { email }, + }; + + const result = await service.processIdentity( + email, + ip, + sessionId, + clientSessionId, + diPersistentSessionId + ); + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/reset-password-check-email/tests/reset-password-check-email-service.test.ts b/src/components/reset-password-check-email/tests/reset-password-check-email-service.test.ts new file mode 100644 index 0000000000..f1ad054882 --- /dev/null +++ b/src/components/reset-password-check-email/tests/reset-password-check-email-service.test.ts @@ -0,0 +1,64 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { Http } from "../../../utils/http"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../test/helpers/service-test-helper"; +import { API_ENDPOINTS, HTTP_STATUS_CODES } from "../../../app.constants"; +import { ResetPasswordCheckEmailServiceInterface } from "../types"; +import { resetPasswordCheckEmailService } from "../reset-password-check-email-service"; + +describe("reset password check email service", () => { + const httpInstance = new Http(); + const service: ResetPasswordCheckEmailServiceInterface = + resetPasswordCheckEmailService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to make a request to reset a password ", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.NO_CONTENT, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { email, sessionId, clientSessionId, ip, diPersistentSessionId } = + commonVariables; + const withinForcedPasswordResetJourney = false; + + const result = await service.resetPasswordRequest( + email, + sessionId, + ip, + clientSessionId, + diPersistentSessionId, + withinForcedPasswordResetJourney + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.RESET_PASSWORD_REQUEST, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { withinForcedPasswordResetJourney, email }, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/src/components/reset-password/tests/reset-password-service.test.ts b/src/components/reset-password/tests/reset-password-service.test.ts new file mode 100644 index 0000000000..87e7301fa8 --- /dev/null +++ b/src/components/reset-password/tests/reset-password-service.test.ts @@ -0,0 +1,65 @@ +import { describe } from "mocha"; +import sinon, { SinonStub } from "sinon"; +import { ResetPasswordServiceInterface } from "../types"; +import { resetPasswordService } from "../reset-password-service"; +import { Http } from "../../../utils/http"; +import { + checkApiCallMadeWithExpectedBodyAndHeaders, + commonVariables, + expectedHeadersFromCommonVarsWithoutSecurityHeaders, + resetApiKeyAndBaseUrlEnvVars, + setupApiKeyAndBaseUrlEnvVars, +} from "../../../../test/helpers/service-test-helper"; +import { API_ENDPOINTS, HTTP_STATUS_CODES } from "../../../app.constants"; + +describe("reset password service", () => { + const httpInstance = new Http(); + const service: ResetPasswordServiceInterface = + resetPasswordService(httpInstance); + let postStub: SinonStub; + + beforeEach(() => { + setupApiKeyAndBaseUrlEnvVars(); + postStub = sinon.stub(httpInstance.client, "post"); + }); + + afterEach(() => { + postStub.reset(); + resetApiKeyAndBaseUrlEnvVars(); + }); + + it("successfully calls the API to update a password", async () => { + const axiosResponse = Promise.resolve({ + data: {}, + status: HTTP_STATUS_CODES.NO_CONTENT, + statusText: "OK", + }); + postStub.resolves(axiosResponse); + const { sessionId, clientSessionId, ip, diPersistentSessionId } = + commonVariables; + const newPassword = "abcdef"; + const isForcedPasswordReset = false; + + const result = await service.updatePassword( + newPassword, + ip, + sessionId, + clientSessionId, + diPersistentSessionId, + isForcedPasswordReset + ); + + const expectedApiCallDetails = { + expectedPath: API_ENDPOINTS.RESET_PASSWORD, + expectedHeaders: expectedHeadersFromCommonVarsWithoutSecurityHeaders, + expectedBody: { password: newPassword }, + }; + + checkApiCallMadeWithExpectedBodyAndHeaders( + result, + postStub, + true, + expectedApiCallDetails + ); + }); +}); diff --git a/test/helpers/service-test-helper.ts b/test/helpers/service-test-helper.ts new file mode 100644 index 0000000000..8acd8dde81 --- /dev/null +++ b/test/helpers/service-test-helper.ts @@ -0,0 +1,64 @@ +import { ApiResponseResult } from "../../src/types"; +import { SinonStub } from "sinon"; +import { expect } from "chai"; +import { sinon } from "../utils/test-utils"; + +export const commonVariables = { + email: "joe.bloggs@example.com", + sessionId: "some-session-id", + diPersistentSessionId: "some-persistent-session-id", + clientSessionId: "some-client-session-id", + ip: "123.123.123.123", + apiKey: "apiKey", +}; + +export const expectedHeadersFromCommonVarsWithoutSecurityHeaders = { + "X-API-Key": commonVariables.apiKey, + "Session-Id": commonVariables.sessionId, + "Client-Session-Id": commonVariables.clientSessionId, + "X-Forwarded-For": commonVariables.ip, + "di-persistent-session-id": commonVariables.diPersistentSessionId, +}; + +export interface StubCallExpectations { + expectedPath: string; + expectedHeaders: object; + expectedBody: object; + validateStatus?: boolean; +} + +export function checkApiCallMadeWithExpectedBodyAndHeaders( + result: ApiResponseResult, + stub: SinonStub, + expectedSuccess: boolean, + expectations: StubCallExpectations +): void { + expect(result.success).to.eq(expectedSuccess); + + const expectedValidateStatus = expectations.validateStatus + ? { validateStatus: sinon.match.func } + : {}; + + expect( + stub.calledOnceWithExactly( + expectations.expectedPath, + expectations.expectedBody, + { + headers: expectations.expectedHeaders, + proxy: sinon.match.bool, + ...expectedValidateStatus, + } + ) + ).to.be.true; +} + +export function setupApiKeyAndBaseUrlEnvVars(): void { + process.env.API_KEY = commonVariables.apiKey; + process.env.FRONTEND_API_BASE_URL = "https://example-base-url"; +} + +export function resetApiKeyAndBaseUrlEnvVars(): void { + process.env.API_KEY = commonVariables.apiKey; + process.env.FRONTEND_API_BASE_URL = "https://example-base-url"; + sinon.restore(); +}