@causalfoundry/js-sdk
Version:
Causal Foundry WEB SDK (JS/TS)
455 lines (402 loc) • 12.6 kB
text/typescript
/**
* @jest-environment jsdom
*/
import CfCore from "../../../core/CfCore";
import ECommerce from "..";
import {
ECommerceTypes,
ItemType,
StockStatus,
ItemProperties,
ItemAction,
} from "../typings";
import { CurrencyCode } from "../../../core/commonTypes";
import { ContentBlock } from "../../Navigation/typings";
let windowSpy;
let mockSender;
let mockImpressionManager = {
on: () => {},
};
const device_id = "asdf";
describe("ECommerce", () => {
beforeEach(() => {
mockSender = {
add() {
return false;
},
sendException() {
return false;
},
};
windowSpy = jest.spyOn(window, "window", "get");
});
afterEach(() => {
// to remove the singleton instance
(CfCore as any).instance = null;
});
it('Should deliver a "Item" event', async () => {
const senderSpy = jest.spyOn(mockSender, "add");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: 90,
type: ItemType.Drug,
quantity: 1,
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
await ECommerce.logIngestEvent(ECommerceTypes.Item, event, true);
expect(senderSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: ECommerceTypes.Item,
ctx: expect.objectContaining({
// El item se transforma por getPayloadFromItem y serializeToFlatPrimitiveMap
drug_id: "111", // Se agrega dinámicamente basado en el type
price: 90,
type: ItemType.Drug,
quantity: 1,
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
}),
}),
true,
expect.anything()
);
});
it("Should throw exception and call sendException when quantity is negative", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: 90,
type: ItemType.Drug,
quantity: -1, // Negative quantity
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to negative quantity
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
it("Should throw exception and call sendException when price is negative", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: -50, // Negative price
type: ItemType.Drug,
quantity: 1,
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to negative price
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
it("Should throw exception and call sendException when id is missing", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: undefined as any, // Empty id
price: 90,
type: ItemType.Drug,
quantity: 1,
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to missing id
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
it("Should throw exception and call sendException when type is missing", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: 90,
type: undefined as any, // Missing type
quantity: 1,
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to missing type
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
it("Should throw exception and call sendException when currency is missing", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: 90,
type: ItemType.Drug,
quantity: 1,
promo_id: "11111",
currency: undefined as any, // Missing currency
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to missing currency
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
it("Should throw exception and call sendException when price is missing", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: undefined as any, // Missing price
type: ItemType.Drug,
quantity: 1,
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to missing price
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
it("Should throw exception and call sendException when quantity is missing", async () => {
const addSpy = jest.spyOn(mockSender, "add");
const sendExceptionSpy = jest.spyOn(mockSender, "sendException");
const cfCore = CfCore.createInstance(
mockSender as any,
mockImpressionManager as any,
false,
ContentBlock.Core,
device_id,
false
);
const event: ItemProperties = {
action: ItemAction.View,
item: {
id: "111",
price: 90,
type: ItemType.Drug,
quantity: undefined as any, // Missing quantity
promo_id: "11111",
currency: CurrencyCode.EUR,
stock_status: StockStatus.InStock,
},
};
// The function should throw an exception due to missing quantity
await expect(
ECommerce.logIngestEvent(ECommerceTypes.Item, event, true)
).rejects.toThrow();
// add() should be called with an exception event when validation fails
expect(addSpy).toHaveBeenCalledWith(
expect.stringMatching(device_id),
expect.stringMatching(device_id),
expect.objectContaining({
name: "exception",
property: "item",
ctx: expect.objectContaining({
event_type: "item",
exception_type: "Error",
exception_source: "JS-SDK",
}),
}),
false,
false
);
// sendException() should not be called (exceptions are logged via add)
expect(sendExceptionSpy).not.toHaveBeenCalled();
});
});