teamdigitale/italia-app

View on GitHub
ts/features/messages/saga/__test__/handleLoadMessageData.test.ts

Summary

Maintainability
F
3 wks
Test Coverage
import { testSaga } from "redux-saga-test-plan";
import * as pot from "@pagopa/ts-commons/lib/pot";
import * as O from "fp-ts/lib/Option";
import { testable } from "../handleLoadMessageData";
import { UIMessage, UIMessageDetails, UIMessageId } from "../../types";
import { getPaginatedMessageById } from "../../store/reducers/paginatedById";
import {
  getMessageDataAction,
  loadMessageById,
  loadMessageDetails,
  loadThirdPartyMessage,
  upsertMessageStatusAttributes
} from "../../store/actions";
import { ServiceId } from "../../../../../definitions/backend/ServiceId";
import { serviceByIdPotSelector } from "../../../services/details/store/reducers";
import { loadServiceDetail } from "../../../services/details/store/actions/details";
import { messageDetailsByIdSelector } from "../../store/reducers/detailsById";
import { ThirdPartyMessageWithContent } from "../../../../../definitions/backend/ThirdPartyMessageWithContent";
import { thirdPartyFromIdSelector } from "../../store/reducers/thirdPartyById";
import { TagEnum } from "../../../../../definitions/backend/MessageCategoryPN";
import { isPnEnabledSelector } from "../../../../store/reducers/backendStatus";
import { isLoadingOrUpdatingInbox } from "../../store/reducers/allPaginated";
import { ThirdPartyMessage } from "../../../../../definitions/backend/ThirdPartyMessage";
import { ThirdPartyAttachment } from "../../../../../definitions/backend/ThirdPartyAttachment";
import { ServicePublic } from "../../../../../definitions/backend/ServicePublic";
import { trackMessageDataLoadFailure } from "../../analytics";
import { MessageGetStatusFailurePhaseType } from "../../store/reducers/messageGetStatus";

jest.mock("../../../../config.ts", () => ({
  ...jest.requireActual("../../../../config.ts"),
  euCovidCertificateEnabled: true
}));

describe("getPaginatedMessage", () => {
  it("when no paginated message is in store, it should dispatch a loadMessageById.request and retrieve its result from the store if it succeeds", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const paginatedMessage = { id: messageId } as UIMessage;
    testSaga(testable!.getPaginatedMessage, messageId)
      .next()
      .select(getPaginatedMessageById, messageId)
      .next(pot.none)
      .put(loadMessageById.request({ id: messageId }))
      .next()
      .take([loadMessageById.success, loadMessageById.failure])
      .next(loadMessageById.success(paginatedMessage))
      .select(getPaginatedMessageById, messageId)
      .next(pot.some(paginatedMessage))
      .returns(paginatedMessage);
  });
  it("when an error is in store, it should dispatch a loadMessageById.request and retrieve its result from the store if it succeeds", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const paginatedMessage = { id: messageId } as UIMessage;
    testSaga(testable!.getPaginatedMessage, messageId)
      .next()
      .select(getPaginatedMessageById, messageId)
      .next(pot.noneError)
      .put(loadMessageById.request({ id: messageId }))
      .next()
      .take([loadMessageById.success, loadMessageById.failure])
      .next(loadMessageById.success(paginatedMessage))
      .select(getPaginatedMessageById, messageId)
      .next(pot.some(paginatedMessage))
      .returns(paginatedMessage);
  });
  it("when a paginated message with error is in store, it should dispatch a loadMessageById.request and retrieve its result from the store if it succeeds", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const paginatedMessage = { id: messageId } as UIMessage;
    testSaga(testable!.getPaginatedMessage, messageId)
      .next()
      .select(getPaginatedMessageById, messageId)
      .next(pot.someError(paginatedMessage, new Error()))
      .put(loadMessageById.request({ id: messageId }))
      .next()
      .take([loadMessageById.success, loadMessageById.failure])
      .next(loadMessageById.success(paginatedMessage))
      .select(getPaginatedMessageById, messageId)
      .next(pot.some(paginatedMessage))
      .returns(paginatedMessage);
  });
  it("when the paginated message is in store, it should return it", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const paginatedMessage = { id: messageId } as UIMessage;
    testSaga(testable!.getPaginatedMessage, messageId)
      .next()
      .select(getPaginatedMessageById, messageId)
      .next(pot.some(paginatedMessage))
      .returns(paginatedMessage);
  });
  it("when no paginated message is in store, it should dispatch a loadMessageById.request but return undefined if the related saga fails", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    testSaga(testable!.getPaginatedMessage, messageId)
      .next()
      .select(getPaginatedMessageById, messageId)
      .next(pot.none)
      .put(loadMessageById.request({ id: messageId }))
      .next()
      .take([loadMessageById.success, loadMessageById.failure])
      .next(loadMessageById.failure({ id: messageId, error: new Error() }))
      .returns(undefined);
  });
});

describe("getService", () => {
  it("when no service is in store, it should dispatch a loadServiceDetail.request and retrieve its result from the store if it succeeds", () => {
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceDetails = { service_id: serviceId } as ServicePublic;
    testSaga(testable!.getServiceDetails, serviceId)
      .next()
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.none)
      .put(loadServiceDetail.request(serviceId))
      .next()
      .take([loadServiceDetail.success, loadServiceDetail.failure])
      .next(loadServiceDetail.success(serviceDetails))
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.some(serviceDetails))
      .returns(serviceDetails);
  });
  it("when an error is in store, it should dispatch a loadServiceDetail.request and retrieve its result from the store if it succeeds", () => {
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceDetails = { service_id: serviceId } as ServicePublic;
    testSaga(testable!.getServiceDetails, serviceId)
      .next()
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.noneError)
      .put(loadServiceDetail.request(serviceId))
      .next()
      .take([loadServiceDetail.success, loadServiceDetail.failure])
      .next(loadServiceDetail.success(serviceDetails))
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.some(serviceDetails))
      .returns(serviceDetails);
  });
  it("when a service with error is in store, it should dispatch a loadServiceDetail.request and retrieve its result from the store if it succeeds", () => {
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceDetails = { service_id: serviceId } as ServicePublic;
    testSaga(testable!.getServiceDetails, serviceId)
      .next()
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.someError({}, new Error()))
      .put(loadServiceDetail.request(serviceId))
      .next()
      .take([loadServiceDetail.success, loadServiceDetail.failure])
      .next(loadServiceDetail.success(serviceDetails))
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.some(serviceDetails))
      .returns(serviceDetails);
  });
  it("when a service is in store, it should return its details", () => {
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceDetails = { service_id: serviceId } as ServicePublic;
    testSaga(testable!.getServiceDetails, serviceId)
      .next()
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.some(serviceDetails))
      .returns(serviceDetails);
  });
  it("when no service is in store, it should dispatch a loadServiceDetail.request but return undefined if the related saga fails", () => {
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    testSaga(testable!.getServiceDetails, serviceId)
      .next()
      .select(serviceByIdPotSelector, serviceId)
      .next(pot.none)
      .put(loadServiceDetail.request(serviceId))
      .next()
      .take([loadServiceDetail.success, loadServiceDetail.failure])
      .next(
        loadServiceDetail.failure({ service_id: serviceId, error: new Error() })
      )
      .returns(undefined);
  });
});

describe("getMessageDetails", () => {
  it("when no message details are in store, it should dispatch a loadMessageDetails.request and retrieve its result from the store if it succeeds", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const messageDetails = { id: messageId } as UIMessageDetails;
    testSaga(testable!.getMessageDetails, messageId)
      .next()
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.none)
      .put(loadMessageDetails.request({ id: messageId }))
      .next()
      .take([loadMessageDetails.success, loadMessageDetails.failure])
      .next(loadMessageDetails.success(messageDetails))
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.some(messageDetails))
      .returns(messageDetails);
  });
  it("when an error is in store, it should dispatch a loadMessageDetails.request and retrieve its result from the store if it succeeds", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const messageDetails = { id: messageId } as UIMessageDetails;
    testSaga(testable!.getMessageDetails, messageId)
      .next()
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.noneError)
      .put(loadMessageDetails.request({ id: messageId }))
      .next()
      .take([loadMessageDetails.success, loadMessageDetails.failure])
      .next(loadMessageDetails.success(messageDetails))
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.some(messageDetails))
      .returns(messageDetails);
  });
  it("when some message details with error are in store, it should dispatch a loadMessageDetails.request and retrieve its result from the store if it succeeds", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const messageDetails = { id: messageId } as UIMessageDetails;
    testSaga(testable!.getMessageDetails, messageId)
      .next()
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.someError(messageDetails, new Error()))
      .put(loadMessageDetails.request({ id: messageId }))
      .next()
      .take([loadMessageDetails.success, loadMessageDetails.failure])
      .next(loadMessageDetails.success(messageDetails))
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.some(messageDetails))
      .returns(messageDetails);
  });
  it("when the message details are in store, it should return them", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const messageDetails = { id: messageId } as UIMessageDetails;
    testSaga(testable!.getMessageDetails, messageId)
      .next()
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.some(messageDetails))
      .returns(messageDetails);
  });
  it("when no message details are in store, it should dispatch a loadMessageDetails.request but return undefined if the related saga fails", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    testSaga(testable!.getMessageDetails, messageId)
      .next()
      .select(messageDetailsByIdSelector, messageId)
      .next(pot.none)
      .put(loadMessageDetails.request({ id: messageId }))
      .next()
      .take([loadMessageDetails.success, loadMessageDetails.failure])
      .next(loadMessageDetails.failure({ id: messageId, error: new Error() }))
      .returns(undefined);
  });
});

describe("getThirdPartyDataMessage", () => {
  it("should dispatch a loadThirdPartyMessage.request and return the third party message when the related saga succeeds ", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const service = {
      service_id: "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId,
      service_name: "The name",
      organization_name: "Org name",
      organization_fiscal_code: "OrgFisCod"
    } as ServicePublic;
    const messageCategoryTag = "GENERIC";
    const thirdPartyMessage = { id: "1" } as ThirdPartyMessageWithContent;
    testSaga(
      testable!.getThirdPartyDataMessage,
      messageId,
      false,
      service,
      messageCategoryTag
    )
      .next()
      .put(
        loadThirdPartyMessage.request({
          id: messageId,
          serviceId: service.service_id,
          tag: messageCategoryTag
        })
      )
      .next()
      .take([loadThirdPartyMessage.success, loadThirdPartyMessage.failure])
      .next(
        loadThirdPartyMessage.success({
          id: messageId,
          content: thirdPartyMessage
        })
      )
      .select(thirdPartyFromIdSelector, messageId)
      .next(pot.some(thirdPartyMessage))
      .call(
        testable!.decodeAndTrackThirdPartyMessageDetailsIfNeeded,
        false,
        thirdPartyMessage,
        service,
        messageCategoryTag
      )
      .next(O.none)
      .returns(thirdPartyMessage);
  });
  it("should dispatch a loadThirdPartyMessage.request and return undefined when the related saga fails ", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const service = {
      service_id: "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId,
      service_name: "The name",
      organization_name: "Org name",
      organization_fiscal_code: "OrgFisCod"
    } as ServicePublic;
    const messageCategoryTag = "GENERIC";
    testSaga(
      testable!.getThirdPartyDataMessage,
      messageId,
      false,
      service,
      messageCategoryTag
    )
      .next()
      .put(
        loadThirdPartyMessage.request({
          id: messageId,
          serviceId: service.service_id,
          tag: messageCategoryTag
        })
      )
      .next()
      .take([loadThirdPartyMessage.success, loadThirdPartyMessage.failure])
      .next(
        loadThirdPartyMessage.failure({ id: messageId, error: new Error() })
      )
      .returns(undefined);
  });
});

describe("setMessageReadIfNeeded", () => {
  it("should dispatch an upsertMessageStatusAttributes.request to tag the message as read (if not so already) and return true if such operation succeeds", () => {
    const paginatedMessage = { isRead: false } as UIMessage;
    testSaga(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next()
      .put(
        upsertMessageStatusAttributes.request({
          message: paginatedMessage,
          update: { tag: "reading" }
        })
      )
      .next()
      .take([
        upsertMessageStatusAttributes.success,
        upsertMessageStatusAttributes.failure
      ])
      .next(
        upsertMessageStatusAttributes.success({
          message: paginatedMessage,
          update: { tag: "reading" }
        })
      )
      .returns(true);
  });
  it("should return undefined after having dispatched an upsertMessageStatusAttributes.request to tag the message as read (if not so already) but with a failing result", () => {
    const paginatedMessage = { isRead: false } as UIMessage;
    testSaga(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next()
      .put(
        upsertMessageStatusAttributes.request({
          message: paginatedMessage,
          update: { tag: "reading" }
        })
      )
      .next()
      .take([
        upsertMessageStatusAttributes.success,
        upsertMessageStatusAttributes.failure
      ])
      .next(
        upsertMessageStatusAttributes.failure({
          payload: {
            message: paginatedMessage,
            update: { tag: "reading" }
          },
          error: new Error()
        })
      )
      .returns(undefined);
  });
  it("should return true is the message is read", () => {
    const paginatedMessage = { isRead: true } as UIMessage;
    testSaga(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next()
      .returns(true);
  });
});

describe("dispatchSuccessAction", () => {
  it("should properly report a PN message", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceName = "serName";
    const organizationName = "orgName";
    const organizationFiscalCode = "orgFisCod";
    const isRead = true;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      organizationName,
      organizationFiscalCode,
      serviceName,
      isRead,
      category: { tag: TagEnum.PN }
    } as UIMessage;
    const messageDetails = {} as UIMessageDetails;
    const thirdPartyMessage = {
      third_party_message: {
        attachments: [{} as ThirdPartyAttachment]
      } as ThirdPartyMessage
    } as ThirdPartyMessageWithContent;
    const expectedOutput = {
      containsAttachments: true,
      containsPayment: undefined,
      euCovidCerficateAuthCode: undefined,
      firstTimeOpening: !isRead,
      hasRemoteContent: true,
      isPNMessage: true,
      messageId,
      organizationName,
      organizationFiscalCode,
      serviceId,
      serviceName
    };
    testSaga(
      testable!.dispatchSuccessAction,
      paginatedMessage,
      messageDetails,
      thirdPartyMessage
    )
      .next()
      .select(isPnEnabledSelector)
      .next(true)
      .put(getMessageDataAction.success(expectedOutput))
      .next()
      .isDone();
  });
  it("should properly report a Third Party message with attachments", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceName = "serName";
    const organizationName = "orgName";
    const organizationFiscalCode = "orgFisCod";
    const isRead = true;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      organizationName,
      organizationFiscalCode,
      serviceName,
      isRead,
      category: { tag: "GENERIC" }
    } as UIMessage;
    const messageDetails = {} as UIMessageDetails;
    const thirdPartyMessage = {
      third_party_message: {
        attachments: [{} as ThirdPartyAttachment]
      } as ThirdPartyMessage
    } as ThirdPartyMessageWithContent;
    const expectedOutput = {
      containsAttachments: true,
      containsPayment: false,
      euCovidCerficateAuthCode: undefined,
      firstTimeOpening: !isRead,
      hasRemoteContent: true,
      isPNMessage: false,
      messageId,
      organizationName,
      organizationFiscalCode,
      serviceId,
      serviceName
    };
    testSaga(
      testable!.dispatchSuccessAction,
      paginatedMessage,
      messageDetails,
      thirdPartyMessage
    )
      .next()
      .select(isPnEnabledSelector)
      .next(true)
      .put(getMessageDataAction.success(expectedOutput))
      .next()
      .isDone();
  });
  it("should properly report a Third Party message with no attachments", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceName = "serName";
    const organizationName = "orgName";
    const organizationFiscalCode = "orgFisCod";
    const isRead = true;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      organizationName,
      organizationFiscalCode,
      serviceName,
      isRead,
      category: { tag: "GENERIC" }
    } as UIMessage;
    const messageDetails = {} as UIMessageDetails;
    const thirdPartyMessage = {
      third_party_message: {} as ThirdPartyMessage
    } as ThirdPartyMessageWithContent;
    const expectedOutput = {
      containsAttachments: false,
      containsPayment: false,
      euCovidCerficateAuthCode: undefined,
      firstTimeOpening: !isRead,
      hasRemoteContent: true,
      isPNMessage: false,
      messageId,
      organizationName,
      organizationFiscalCode,
      serviceId,
      serviceName
    };
    testSaga(
      testable!.dispatchSuccessAction,
      paginatedMessage,
      messageDetails,
      thirdPartyMessage
    )
      .next()
      .select(isPnEnabledSelector)
      .next(true)
      .put(getMessageDataAction.success(expectedOutput))
      .next()
      .isDone();
  });
  it("should properly report a message without Payment", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceName = "serName";
    const organizationName = "orgName";
    const organizationFiscalCode = "orgFisCod";
    const isRead = true;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      organizationName,
      organizationFiscalCode,
      serviceName,
      isRead,
      category: { tag: "GENERIC" }
    } as UIMessage;
    const messageDetails = {} as UIMessageDetails;
    const expectedOutput = {
      containsAttachments: false,
      containsPayment: false,
      euCovidCerficateAuthCode: undefined,
      firstTimeOpening: !isRead,
      hasRemoteContent: false,
      isPNMessage: false,
      messageId,
      organizationName,
      organizationFiscalCode,
      serviceId,
      serviceName
    };
    testSaga(
      testable!.dispatchSuccessAction,
      paginatedMessage,
      messageDetails,
      undefined
    )
      .next()
      .select(isPnEnabledSelector)
      .next(false)
      .put(getMessageDataAction.success(expectedOutput))
      .next()
      .isDone();
  });
  it("should properly report a message with Payment", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceName = "serName";
    const organizationName = "orgName";
    const organizationFiscalCode = "orgFisCod";
    const isRead = true;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      organizationName,
      organizationFiscalCode,
      serviceName,
      isRead,
      category: { tag: "GENERIC" }
    } as UIMessage;
    const messageDetails = { paymentData: {} } as UIMessageDetails;
    const expectedOutput = {
      containsAttachments: false,
      containsPayment: true,
      euCovidCerficateAuthCode: undefined,
      firstTimeOpening: !isRead,
      hasRemoteContent: false,
      isPNMessage: false,
      messageId,
      organizationName,
      organizationFiscalCode,
      serviceId,
      serviceName
    };
    testSaga(
      testable!.dispatchSuccessAction,
      paginatedMessage,
      messageDetails,
      undefined
    )
      .next()
      .select(isPnEnabledSelector)
      .next(false)
      .put(getMessageDataAction.success(expectedOutput))
      .next()
      .isDone();
  });
  it("should properly report a EU Covid message", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceName = "serName";
    const organizationName = "orgName";
    const organizationFiscalCode = "orgFisCod";
    const isRead = true;
    const authCode = "authCode";
    const paginatedMessage = {
      id: messageId,
      serviceId,
      organizationName,
      organizationFiscalCode,
      serviceName,
      isRead,
      category: { tag: "GENERIC" }
    } as UIMessage;
    const messageDetails = {
      euCovidCertificate: { authCode }
    } as UIMessageDetails;
    const expectedOutput = {
      containsAttachments: false,
      containsPayment: false,
      euCovidCerficateAuthCode: authCode,
      firstTimeOpening: !isRead,
      hasRemoteContent: false,
      isPNMessage: false,
      messageId,
      organizationName,
      organizationFiscalCode,
      serviceId,
      serviceName
    };
    testSaga(
      testable!.dispatchSuccessAction,
      paginatedMessage,
      messageDetails,
      undefined
    )
      .next()
      .select(isPnEnabledSelector)
      .next(false)
      .put(getMessageDataAction.success(expectedOutput))
      .next()
      .isDone();
  });
});

describe("loadMessageData", () => {
  it("should loop while isLoadingOrUpdatingInbox and dispatch a getMessageDataAction.failure if getPaginatedMessage returns a failure", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(undefined)
      .call(testable!.commonFailureHandling, "paginatedMessage", false)
      .next()
      .isDone();
  });
  it("should dispatch a getMessageDataAction.failure if getMessageDetails returns a failure", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const paginatedMessage = { id: messageId, serviceId } as UIMessage;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(undefined)
      .call(testable!.commonFailureHandling, "messageDetails", false)
      .next()
      .isDone();
  });
  it("should dispatch a getMessageDataAction.failure if the action started from a Push Notification for a PN message", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag: TagEnum.PN }
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = {} as UIMessageDetails;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: true
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(testable!.commonFailureHandling, "preconditions", true, true)
      .next()
      .isDone();
  });
  it("should dispatch a getMessageDataAction.failure if the action started from a Push Notification for a message with preconditions", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag: "GENERIC" },
      hasPrecondition: true
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = {} as UIMessageDetails;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: true
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(testable!.commonFailureHandling, "preconditions", true, true)
      .next()
      .isDone();
  });
  it("should dispatch a getMessageDataAction.failure if thirdPartyMessageDetails returns a failure", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const tag = "GENERIC";
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag },
      hasPrecondition: false
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = { hasThirdPartyData: true } as UIMessageDetails;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(
        testable!.getThirdPartyDataMessage,
        messageId,
        false,
        serviceDetails,
        tag
      )
      .next(undefined)
      .call(testable!.commonFailureHandling, "thirdPartyMessageDetails", false)
      .next()
      .isDone();
  });
  it("should dispatch a getMessageDataAction.failure if setMessageReadIfNeeded returns a failure (having retrieved third party data successfully)", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const tag = "GENERIC";
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag },
      hasPrecondition: false
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = { hasThirdPartyData: true } as UIMessageDetails;
    const thirdPartyMessage = {} as ThirdPartyMessageWithContent;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(
        testable!.getThirdPartyDataMessage,
        messageId,
        false,
        serviceDetails,
        tag
      )
      .next(thirdPartyMessage)
      .call(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next(undefined)
      .call(testable!.commonFailureHandling, "readStatusUpdate", false)
      .next()
      .isDone();
  });
  it("should dispatch a getMessageDataAction.failure if setMessageReadIfNeeded returns a failure (with no third party data)", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag: "GENERIC" },
      hasPrecondition: false
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = { hasThirdPartyData: false } as UIMessageDetails;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next(undefined)
      .call(testable!.commonFailureHandling, "readStatusUpdate", false)
      .next()
      .isDone();
  });
  it("should call dispatchSuccessAction when it succeed (having retrieved third party data successfully for a remoted content message)", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const tag = "GENERIC";
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag },
      hasPrecondition: false
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = { hasThirdPartyData: true } as UIMessageDetails;
    const thirdPartyMessage = {} as ThirdPartyMessageWithContent;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(
        testable!.getThirdPartyDataMessage,
        messageId,
        false,
        serviceDetails,
        tag
      )
      .next(thirdPartyMessage)
      .call(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next(true)
      .call(
        testable!.dispatchSuccessAction,
        paginatedMessage,
        messageDetails,
        thirdPartyMessage
      )
      .next()
      .isDone();
  });
  it("should call dispatchSuccessAction when it succeed (having retrieved third party data successfully for a PN message)", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const tag = "PN";
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag },
      hasPrecondition: true
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = {} as UIMessageDetails;
    const thirdPartyMessage = {} as ThirdPartyMessageWithContent;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(
        testable!.getThirdPartyDataMessage,
        messageId,
        true,
        serviceDetails,
        tag
      )
      .next(thirdPartyMessage)
      .call(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next(true)
      .call(
        testable!.dispatchSuccessAction,
        paginatedMessage,
        messageDetails,
        thirdPartyMessage
      )
      .next()
      .isDone();
  });
  it("should call dispatchSuccessAction when it succeed (with no third party data)", () => {
    const messageId = "01HGP8EMP365Y7ANBNK8AJ87WD" as UIMessageId;
    const serviceId = "01J5WS3X839BXX6R1CMM51AB8R" as ServiceId;
    const paginatedMessage = {
      id: messageId,
      serviceId,
      category: { tag: "GENERIC" },
      hasPrecondition: false
    } as UIMessage;
    const serviceDetails = {
      service_id: serviceId
    } as ServicePublic;
    const messageDetails = { hasThirdPartyData: false } as UIMessageDetails;
    testSaga(testable!.loadMessageData, {
      messageId,
      fromPushNotification: false
    })
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(true)
      .delay(500)
      .next()
      .select(isLoadingOrUpdatingInbox)
      .next(false)
      .call(testable!.getPaginatedMessage, messageId)
      .next(paginatedMessage)
      .call(testable!.getServiceDetails, serviceId)
      .next(serviceDetails)
      .call(testable!.getMessageDetails, messageId)
      .next(messageDetails)
      .call(testable!.setMessageReadIfNeeded, paginatedMessage)
      .next(true)
      .call(
        testable!.dispatchSuccessAction,
        paginatedMessage,
        messageDetails,
        undefined
      )
      .next()
      .isDone();
  });
});

describe("commonFailureHandling", () => {
  (
    [
      "none",
      "paginatedMessage",
      "serviceDetails",
      "messageDetails",
      "preconditions",
      "thirdPartyMessageDetails",
      "readStatusUpdate"
    ] as ReadonlyArray<MessageGetStatusFailurePhaseType>
  ).forEach(phase =>
    [false, true].forEach(startedFromPushNotification =>
      [undefined, false, true].forEach(blockedFromPushNotificationOpt => {
        it(`should track analytics and dispatch 'getMessageDataAction.failure', phase '${phase}' (from push notification '${startedFromPushNotification}', blocked on push notification '${!!blockedFromPushNotificationOpt}')`, () => {
          testSaga(
            testable!.commonFailureHandling,
            phase,
            startedFromPushNotification,
            blockedFromPushNotificationOpt
          )
            .next()
            .call(
              trackMessageDataLoadFailure,
              startedFromPushNotification,
              phase
            )
            .next()
            .put(
              getMessageDataAction.failure({
                blockedFromPushNotificationOpt,
                phase
              })
            )
            .next()
            .isDone();
        });
      })
    )
  );
});