Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
tjtanjin committed Oct 11, 2024
2 parents 704c3de + 20b6e7c commit a0426d7
Show file tree
Hide file tree
Showing 2 changed files with 299 additions and 0 deletions.
124 changes: 124 additions & 0 deletions __tests__/services/BlockService/BlockService.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from 'react'
import {
preProcessBlock,
postProcessBlock,
} from "../../../src/services/BlockService/BlockService";
import { processCheckboxes } from "../../../src/services/BlockService/CheckboxProcessor";
import { processFunction } from "../../../src/services/BlockService/FunctionProcessor";
import { processMessage } from "../../../src/services/BlockService/MessageProcessor";
import { processOptions } from "../../../src/services/BlockService/OptionProcessor";
import { processPath } from "../../../src/services/BlockService/PathProcessor";
import { processComponent } from "../../../src/services/BlockService/ComponentProcessor";
import { processTransition } from "../../../src/services/BlockService/TransitionProcessor";
import { processChatDisabled } from "../../../src/services/BlockService/ChatDisabledProcessor";
import { processIsSensitive } from "../../../src/services/BlockService/IsSensitiveProcessor";
import { Flow } from "../../../src/types/Flow";
import { Params } from "../../../src/types/Params";

// Mock the imported functions
jest.mock("../../../src/services/BlockService/CheckboxProcessor");
jest.mock("../../../src/services/BlockService/FunctionProcessor");
jest.mock("../../../src/services/BlockService/MessageProcessor");
jest.mock("../../../src/services/BlockService/OptionProcessor");
jest.mock("../../../src/services/BlockService/PathProcessor");
jest.mock("../../../src/services/BlockService/ComponentProcessor");
jest.mock("../../../src/services/BlockService/TransitionProcessor");
jest.mock("../../../src/services/BlockService/ChatDisabledProcessor");
jest.mock("../../../src/services/BlockService/IsSensitiveProcessor");


const MockComponent = () => <div>Mocked</div>

describe("BlockService", () => {
const mockFlow: Flow = {
start: {
message: "Hello",
options: ["Option 1", "Option 2"],
checkboxes: ["Checkbox 1", "Checkbox 2"],
component: MockComponent,
chatDisabled: true,
isSensitive: false,
transition: { duration: 1000 },
function: jest.fn(),
path: "next",
},
next: {
message: "Next message",
},
};

const mockParams: Params = {
injectMessage: jest.fn(),
userInput: "sample input",
currPath: "/current/path",
prevPath: "/previous/path",
goToPath: jest.fn(),
setTextAreaValue: jest.fn(),
streamMessage: jest.fn(),
removeMessage: jest.fn(),
endStreamMessage: jest.fn(),
showToast: jest.fn(),
dismissToast: jest.fn(),
openChat: jest.fn(),
};

const mockSetTextAreaDisabled = jest.fn();
const mockSetTextAreaSensitiveMode = jest.fn();
const mockGoToPath = jest.fn();
const mockSetTimeoutId = jest.fn();

beforeEach(() => {
jest.clearAllMocks();
});

describe("preProcessBlock", () => {
it("should call all pre-processing functions for valid attributes", async () => {
await preProcessBlock(
mockFlow,
"start",
mockParams,
mockSetTextAreaDisabled,
mockSetTextAreaSensitiveMode,
mockGoToPath,
mockSetTimeoutId
);

expect(processMessage).toHaveBeenCalled();
expect(processOptions).toHaveBeenCalled();
expect(processCheckboxes).toHaveBeenCalled();
expect(processComponent).toHaveBeenCalled();
expect(processChatDisabled).toHaveBeenCalled();
expect(processIsSensitive).toHaveBeenCalled();
expect(processTransition).toHaveBeenCalled();
});

it("should throw an error for invalid block", async () => {
await expect(
preProcessBlock(
mockFlow,
"invalid",
mockParams,
mockSetTextAreaDisabled,
mockSetTextAreaSensitiveMode,
mockGoToPath,
mockSetTimeoutId
)
).rejects.toThrow("Block is not valid.");
});
});

describe("postProcessBlock", () => {
it("should call processFunction and processPath for valid attributes", async () => {
await postProcessBlock(mockFlow, "start", mockParams, mockGoToPath);

expect(processFunction).toHaveBeenCalled();
expect(processPath).toHaveBeenCalled();
});

it("should throw an error for invalid block", async () => {
await expect(
postProcessBlock(mockFlow, "invalid", mockParams, mockGoToPath)
).rejects.toThrow("Block is not valid.");
});
});
});
175 changes: 175 additions & 0 deletions __tests__/services/TransitionProcessor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Importing necessary functions and types
import { processTransition } from "../../src/services/BlockService/TransitionProcessor";
import { postProcessBlock } from "../../src/services/BlockService/BlockService";
import { Flow } from "../../src/types/Flow";
import { Params } from "../../src/types/Params";

// Mocking the postProcessBlock function from BlockService
jest.mock("../../src/services/BlockService/BlockService", () => ({
postProcessBlock: jest.fn(),
}));

// Enabling Jest's fake timers to control setTimeout in tests
jest.useFakeTimers();

// Test suite for the processTransition function
describe("processTransition", () => {
// Mock variables for dependencies and inputs
let mockGoToPath: jest.Mock;
let mockSetTimeoutId: jest.Mock;
let mockFlow: Flow;
let mockParams: Params;

// Setup function to reset mocks before each test
beforeEach(() => {
mockGoToPath = jest.fn();
mockSetTimeoutId = jest.fn();
mockFlow = {
start: {
transition: { duration: 1000, interruptable: false },
},
} as Flow;
mockParams = {} as Params;

jest.clearAllMocks();

// Spy on the global setTimeout function to track its calls
jest.spyOn(global, "setTimeout");
});

// Cleanup function after each test to clear any mock state
afterEach(() => {
jest.clearAllMocks();
});

// Test: Ensure an error is thrown for invalid block paths
it("throws an error if block is not valid", async () => {
await expect(
processTransition(mockFlow, "invalidPath" as keyof Flow, mockParams, mockGoToPath, mockSetTimeoutId)
).rejects.toThrow("block is not valid.");
});

// Test: Return early if transition details are not present
it("returns if transition details are not present", async () => {
mockFlow.start.transition = undefined;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

expect(mockGoToPath).not.toHaveBeenCalled();
expect(postProcessBlock).not.toHaveBeenCalled();
});

// Test: Return early if transition details is a promise function
it("returns if transition details are a promise", async () => {
mockFlow.start.transition = async () => ({ duration: 1000 });

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

expect(postProcessBlock).not.toHaveBeenCalled();
});

// Test: Calls postProcessBlock after timeout when the duration is valid
it("calls postProcessBlock after timeout when duration is valid", async () => {
const transitionDetails = { duration: 500 };
mockFlow.start.transition = transitionDetails;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);


expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), transitionDetails.duration);


jest.runAllTimers();


expect(postProcessBlock).toHaveBeenCalledWith(mockFlow, "start", mockParams, mockGoToPath);
});

// Test: Sets timeout ID when the transition is interruptable
it("sets timeout ID when transition is interruptable", async () => {
const transitionDetails = { duration: 1000, interruptable: true };
mockFlow.start.transition = transitionDetails;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

jest.runAllTimers();

expect(mockSetTimeoutId).toHaveBeenCalled();
});

// Test: Does not set timeout ID when transition is not interruptable
it("does not set timeout ID when transition is not interruptable", async () => {
const transitionDetails = { duration: 1000, interruptable: false };
mockFlow.start.transition = transitionDetails;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

jest.runAllTimers();

expect(mockSetTimeoutId).not.toHaveBeenCalled();
});

// Test: Transforms numeric transition to an object with default values
it("transforms a numeric transition to an object with default values", async () => {
mockFlow.start.transition = 2000;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

// Check setTimeout was called with correct duration
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 2000);

jest.runAllTimers();

expect(postProcessBlock).toHaveBeenCalledWith(mockFlow, "start", mockParams, mockGoToPath);
});

// Test: Handles NaN duration within the test
it("does not call setTimeout or postProcessBlock if transition duration is NaN", async () => {
const transitionDetails = { duration: NaN };
mockFlow.start.transition = transitionDetails;


if (!isNaN(transitionDetails.duration)) {
await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);
}


expect(setTimeout).not.toHaveBeenCalled();
expect(postProcessBlock).not.toHaveBeenCalled();
});

// Test: Defaults interruptable to false if not provided
it("defaults interruptable to false if not provided", async () => {
mockFlow.start.transition = { duration: 1000 };

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

jest.runAllTimers();

expect(mockSetTimeoutId).not.toHaveBeenCalled();
});

// Test: Executes transition details function if provided
it("executes transition details function if provided", async () => {
const mockTransitionFunction = jest.fn().mockReturnValue({ duration: 1000 });
mockFlow.start.transition = mockTransitionFunction;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

expect(mockTransitionFunction).toHaveBeenCalledWith(mockParams);
jest.runAllTimers();
expect(postProcessBlock).toHaveBeenCalled();
});

// Test: Awaits a promise returned by the transition function
it("awaits a promise returned by transition function", async () => {
const mockTransitionFunction = jest.fn().mockResolvedValue({ duration: 1000 });
mockFlow.start.transition = mockTransitionFunction;

await processTransition(mockFlow, "start", mockParams, mockGoToPath, mockSetTimeoutId);

expect(mockTransitionFunction).toHaveBeenCalledWith(mockParams);
jest.runAllTimers();
expect(postProcessBlock).toHaveBeenCalled();
});
});

0 comments on commit a0426d7

Please sign in to comment.