-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test: Add a bunch of tests using Copilot
- Loading branch information
Showing
7 changed files
with
745 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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([]); | ||
}); | ||
}); |
Oops, something went wrong.