Skip to content

Commit

Permalink
Test: Add a bunch of tests using Copilot
Browse files Browse the repository at this point in the history
  • Loading branch information
Gum-Joe committed Aug 5, 2024
1 parent 696311c commit d0171ca
Show file tree
Hide file tree
Showing 7 changed files with 745 additions and 5 deletions.
2 changes: 1 addition & 1 deletion email/libmailmerge/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export default {
transformIgnorePatterns: ["/node_modules/(?!(@docsoc|chalk)/)", "\\.pnp\\.[^\\/]+$"],
moduleFileExtensions: ["ts", "js", "html"],
coverageDirectory: "../../coverage/email/mailmerge-cli",
testMatch: ["<rootDir>/test/**/*.ts"],
testMatch: ["<rootDir>/test/**/*.ts", "<rootDir>/src/**/*.spec.ts"],
};
153 changes: 153 additions & 0 deletions email/libmailmerge/src/pipelines/generate.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { createLogger } from "@docsoc/util";

import { TemplateEngine, TemplateEngineOptions, TemplatePreviews } from "../engines/index.js";
import { validateRecord, createEmailData } from "../previews/index.js";
import { generatePreviews, GenerateOptions } from "./generate";
import { DataSource } from "./loaders";
import { StorageBackend, MergeResult } from "./storage/types";

jest.mock("@docsoc/util");
jest.mock("@docsoc/util", () => ({
createLogger: () => ({
info: jest.fn(),
debug: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
}),
move: jest.fn(),
}));
jest.mock("../engines/index.js");
jest.mock("../previews/index.js");
jest.mock("./loaders");
jest.mock("./storage/types");

describe("generatePreviews", () => {
let mockDataSource: DataSource;
let mockStorageBackend: StorageBackend;
let mockEngine: TemplateEngine;

beforeEach(() => {
mockDataSource = {
loadRecords: jest.fn().mockResolvedValue({
headers: new Set(["header1", "header2"]),
records: [{ header1: "value1", header2: "value2" }],
}),
};

/// @ts-expect-error: Mocking storage backend
mockStorageBackend = {
storeOriginalMergeResults: jest.fn().mockResolvedValue(undefined),
};

/// @ts-expect-error: Mocking engine
mockEngine = {
loadTemplate: jest.fn().mockResolvedValue(undefined),
extractFields: jest.fn().mockReturnValue(new Set(["field1", "field2"])),
/// @ts-expect-error: Mocking engine method
renderPreview: jest.fn().mockResolvedValue({ preview: "preview" } as TemplatePreviews),
};

(validateRecord as jest.Mock).mockReturnValue({ valid: true });
(createEmailData as jest.Mock).mockReturnValue({ email: "emailData" });
});

it("should generate previews with minimal valid options", async () => {
const options: GenerateOptions = {
engineInfo: {
name: "testEngine",
options: {} as TemplateEngineOptions,
engine: mockEngine,
},
features: {},
dataSource: mockDataSource,
storageBackend: mockStorageBackend,
mappings: {
headersToTemplateMap: new Map([
["header1", "field1"],
["header2", "field2"],
]),
keysForAttachments: [],
},
};

await generatePreviews(options);

expect(mockDataSource.loadRecords).toHaveBeenCalled();
expect(mockEngine.loadTemplate).toHaveBeenCalled();
expect(mockEngine.extractFields).toHaveBeenCalled();
expect(mockEngine.renderPreview).toHaveBeenCalled();
expect(mockStorageBackend.storeOriginalMergeResults).toHaveBeenCalled();
});

it("should handle attachments provided in options", async () => {
const options: GenerateOptions = {
engineInfo: {
name: "testEngine",
options: {} as TemplateEngineOptions,
engine: mockEngine,
},
features: {},
dataSource: mockDataSource,
storageBackend: mockStorageBackend,
mappings: {
headersToTemplateMap: new Map([
["header1", "field1"],
["header2", "field2"],
]),
keysForAttachments: [],
},
attachments: ["attachment1", "attachment2"],
};

await generatePreviews(options);
});

it("should enable CC and BCC mapping from records", async () => {
const options: GenerateOptions = {
engineInfo: {
name: "testEngine",
options: {} as TemplateEngineOptions,
engine: mockEngine,
},
features: {
enableCC: true,
enableBCC: true,
},
dataSource: mockDataSource,
storageBackend: mockStorageBackend,
mappings: {
headersToTemplateMap: new Map([
["header1", "field1"],
["header2", "field2"],
]),
keysForAttachments: [],
},
};

await generatePreviews(options);
});

it("should skip invalid records", async () => {
(validateRecord as jest.Mock).mockReturnValueOnce({ valid: false, reason: "Invalid data" });

const options: GenerateOptions = {
engineInfo: {
name: "testEngine",
options: {} as TemplateEngineOptions,
engine: mockEngine,
},
features: {},
dataSource: mockDataSource,
storageBackend: mockStorageBackend,
mappings: {
headersToTemplateMap: new Map([
["header1", "field1"],
["header2", "field2"],
]),
keysForAttachments: [],
},
};

await generatePreviews(options);
});
});
66 changes: 66 additions & 0 deletions email/libmailmerge/src/pipelines/loaders/csv.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { createLogger } from "@docsoc/util";
import { parse } from "csv-parse";
import fs from "fs/promises";

import { CSVBackend } from "./csv";

jest.mock("fs/promises");
jest.mock("csv-parse");
jest.mock("@docsoc/util");

describe("CSVBackend", () => {
const mockLogger = {
info: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
};

beforeEach(() => {
jest.clearAllMocks();
(createLogger as jest.Mock).mockReturnValue(mockLogger);
});

it("should load and parse CSV records correctly", async () => {
const csvContent = "name,age\nJohn,30\nJane,25";
(fs.readFile as jest.Mock).mockResolvedValue(csvContent);
const mockParse = jest.fn().mockImplementation(function* () {
yield { name: "John", age: "30" };
yield { name: "Jane", age: "25" };
});
(parse as jest.Mock).mockReturnValue(mockParse());

const backend = new CSVBackend("path/to/csv");
const result = await backend.loadRecords();

expect(fs.readFile).toHaveBeenCalledWith("path/to/csv", "utf-8");
expect(parse).toHaveBeenCalledWith(csvContent, { columns: true });
expect(result).toEqual({
headers: new Set(["name", "age"]),
records: [
{ name: "John", age: "30" },
{ name: "Jane", age: "25" },
],
});
});

it("should handle empty CSV", async () => {
const csvContent = "";
(fs.readFile as jest.Mock).mockResolvedValue(csvContent);
// eslint-disable-next-line @typescript-eslint/no-empty-function
const mockParse = jest.fn().mockImplementation(function* () {});
(parse as jest.Mock).mockReturnValue(mockParse());

const backend = new CSVBackend("path/to/csv");

await expect(backend.loadRecords()).rejects.toThrow("No records found in CSV");
expect(mockLogger.error).toHaveBeenCalledWith("No records found in CSV");
});

it("should handle readFile errors", async () => {
(fs.readFile as jest.Mock).mockRejectedValue(new Error("File not found"));

const backend = new CSVBackend("path/to/csv");

await expect(backend.loadRecords()).rejects.toThrow("File not found");
});
});
133 changes: 133 additions & 0 deletions email/libmailmerge/src/pipelines/rerender.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { TemplateEngineConstructor, TemplateEngine } from "../engines/types";
import { rerenderPreviews } from "./rerender";
import { StorageBackend, MergeResultWithMetadata } from "./storage/types";

jest.mock("@docsoc/util", () => ({
createLogger: jest.fn().mockReturnValue({
info: jest.fn(),
debug: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
}),
}));

describe("rerenderPreviews", () => {
let mockStorageBackend: StorageBackend;
let mockEngine: TemplateEngine;
let mockEngineConstructor: jest.MockedClass<TemplateEngineConstructor>;

beforeEach(() => {
/// @ts-expect-error: Mocking storage backend
mockStorageBackend = {
loadMergeResults: jest.fn(),
storeUpdatedMergeResults: jest.fn().mockResolvedValue(undefined),
};

/// @ts-expect-error: Mocking engine
mockEngine = {
loadTemplate: jest.fn().mockResolvedValue(undefined),
rerenderPreviews: jest.fn().mockResolvedValue([
{
name: "newPreview",
content: "newPreviewContent",
metadata: {},
},
]),
};

mockEngineConstructor = jest.fn().mockImplementation(() => mockEngine);
});

it("should rerender previews with valid merge results and engine", async () => {
const mergeResults: MergeResultWithMetadata<unknown>[] = [
{
record: { field1: "value1" },
previews: [
{
name: "oldPreview",
content: "oldPreviewContent",
metadata: {},
},
],
engineInfo: { name: "testEngine", options: {} },
email: { to: ["[email protected]"], cc: [], bcc: [], subject: "" },
attachmentPaths: [],
storageBackendMetadata: {},
},
];
(mockStorageBackend.loadMergeResults as jest.Mock).mockReturnValue(mergeResults);

const enginesMap = {
testEngine: mockEngineConstructor,
};

await rerenderPreviews(mockStorageBackend, enginesMap);

expect(mockStorageBackend.loadMergeResults).toHaveBeenCalled();
expect(mockEngine.loadTemplate).toHaveBeenCalled();
expect(mockEngine.rerenderPreviews).toHaveBeenCalledWith(
[
{
name: "oldPreview",
content: "oldPreviewContent",
metadata: {},
},
],
{
field1: "value1",
},
);
expect(mockStorageBackend.storeUpdatedMergeResults).toHaveBeenCalledWith([
{
...mergeResults[0],
previews: [
{
name: "newPreview",
content: "newPreviewContent",
metadata: {},
},
],
},
]);
});

it("should skip records with invalid engine", async () => {
const mergeResults: MergeResultWithMetadata<unknown>[] = [
{
record: { field1: "value1" },
previews: [],
engineInfo: { name: "invalidEngine", options: {} },
email: { to: ["[email protected]"], cc: [], bcc: [], subject: "" },
attachmentPaths: [],
storageBackendMetadata: {},
},
];
(mockStorageBackend.loadMergeResults as jest.Mock).mockReturnValue(mergeResults);

const enginesMap = {
testEngine: mockEngineConstructor,
};

await rerenderPreviews(mockStorageBackend, enginesMap);

expect(mockStorageBackend.loadMergeResults).toHaveBeenCalled();
expect(mockEngine.loadTemplate).not.toHaveBeenCalled();
expect(mockEngine.rerenderPreviews).not.toHaveBeenCalled();
expect(mockStorageBackend.storeUpdatedMergeResults).toHaveBeenCalledWith([]);
});

it("should handle no merge results", async () => {
(mockStorageBackend.loadMergeResults as jest.Mock).mockReturnValue([]);

const enginesMap = {
testEngine: mockEngineConstructor,
};

await rerenderPreviews(mockStorageBackend, enginesMap);

expect(mockStorageBackend.loadMergeResults).toHaveBeenCalled();
expect(mockEngine.loadTemplate).not.toHaveBeenCalled();
expect(mockEngine.rerenderPreviews).not.toHaveBeenCalled();
expect(mockStorageBackend.storeUpdatedMergeResults).toHaveBeenCalledWith([]);
});
});
Loading

0 comments on commit d0171ca

Please sign in to comment.