Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/queue/__mocks__/@courselit/email-editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Re-export only renderEmailToHtml and types to avoid loading EmailEditor and its dependencies
// This allows us to test the real renderEmailToHtml without loading React UI components
export type {
Email,
EmailBlock,
EmailMeta,
EmailStyle,
BlockComponent,
} from "../../../../packages/email-editor/src/types/email-editor";
export type { BlockRegistry } from "../../../../packages/email-editor/src/types/block-registry";
export { renderEmailToHtml } from "../../../../packages/email-editor/src/lib/email-renderer";
export { defaultEmail } from "../../../../packages/email-editor/src/lib/default-email";
2 changes: 2 additions & 0 deletions apps/queue/__mocks__/css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Mock for CSS imports
export default {};
2 changes: 2 additions & 0 deletions apps/queue/__mocks__/lucide-react.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Mock for lucide-react icons
export const Plus = () => null;
1 change: 1 addition & 0 deletions apps/queue/__mocks__/nanoid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const nanoid = jest.fn(() => "mock-nanoid-id");
4 changes: 4 additions & 0 deletions apps/queue/__mocks__/radix-ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Mock for Radix UI components
export const Popover = { Root: ({ children }: any) => children };
export const PopoverContent = ({ children }: any) => children;
export const PopoverTrigger = ({ children }: any) => children;
9 changes: 9 additions & 0 deletions apps/queue/__mocks__/settings-components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Mock for settings components used by email-editor
import * as React from "react";

export const SettingsSelect = ({ children }: { children?: React.ReactNode }) =>
React.createElement(React.Fragment, null, children);
export const SettingsSection = ({ children }: { children?: React.ReactNode }) =>
React.createElement(React.Fragment, null, children);
export const SettingsSlider = ({ children }: { children?: React.ReactNode }) =>
React.createElement(React.Fragment, null, children);
1 change: 1 addition & 0 deletions apps/queue/__mocks__/slugify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default jest.fn((str: string) => str.toLowerCase().replace(/\s+/g, "-"));
7 changes: 7 additions & 0 deletions apps/queue/__mocks__/ui-components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Mock for UI components that aren't needed for renderEmailToHtml testing
export const Popover = ({ children }: { children: React.ReactNode }) =>
children;
export const PopoverContent = ({ children }: { children: React.ReactNode }) =>
children;
export const PopoverTrigger = ({ children }: { children: React.ReactNode }) =>
children;
13 changes: 13 additions & 0 deletions apps/queue/jest-mongodb-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
mongodbMemoryServerOptions: {
binary: {
version: "7.0.0",
skipMD5: true,
},
instance: {
dbName: "jest",
},
autoStart: false,
},
useSharedDBForAllJestWorkers: true,
};
52 changes: 52 additions & 0 deletions apps/queue/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const config = {
preset: "@shelf/jest-mongodb",
setupFilesAfterEnv: ["<rootDir>/setupTests.ts"],
watchPathIgnorePatterns: ["globalConfig"],
moduleNameMapper: {
"@courselit/utils": "<rootDir>/../../packages/utils/src",
"@courselit/common-logic": "<rootDir>/../../packages/common-logic/src",
"@courselit/common-models":
"<rootDir>/../../packages/common-models/src",
"@courselit/email-editor":
"<rootDir>/__mocks__/@courselit/email-editor.ts",
nanoid: "<rootDir>/__mocks__/nanoid.ts",
"@sindresorhus/slugify": "<rootDir>/__mocks__/slugify.ts",
// Handle @/ paths - prioritize email-editor package paths, then queue app paths
// These must come before the generic @/ pattern
"^@/components/ui/(.*)$":
"<rootDir>/../../packages/email-editor/src/components/ui/$1",
"^@/components/settings/(.*)$":
"<rootDir>/__mocks__/settings-components.tsx",
"^@/components/(.*)$":
"<rootDir>/../../packages/email-editor/src/components/$1",
"^@/lib/(.*)$": "<rootDir>/../../packages/email-editor/src/lib/$1",
"^@/blocks$": "<rootDir>/../../packages/email-editor/src/blocks",
"^@/blocks/(.*)$":
"<rootDir>/../../packages/email-editor/src/blocks/$1",
"^@/types/(.*)$": "<rootDir>/../../packages/email-editor/src/types/$1",
"^@/(.*)$": "<rootDir>/src/$1",
// Mock React UI components and dependencies that aren't available in Node.js
"^@radix-ui/(.*)$": "<rootDir>/__mocks__/radix-ui.ts",
"^lucide-react$": "<rootDir>/__mocks__/lucide-react.ts",
// Mock CSS imports
"\\.css$": "<rootDir>/__mocks__/css.ts",
},
transformIgnorePatterns: ["node_modules/(?!(nanoid)/)"],
extensionsToTreatAsEsm: [],
transform: {
"^.+\\.(ts|tsx)$": [
"ts-jest",
{
tsconfig: {
jsx: "react-jsx",
},
},
],
},
testMatch: ["**/__tests__/**/*.test.ts", "**/?(*.)+(spec|test).ts"],
testPathIgnorePatterns: ["/node_modules/", "/dist/"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"],
testEnvironment: "node",
};

export default config;
4 changes: 4 additions & 0 deletions apps/queue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@shelf/jest-mongodb": "^5.2.2",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.14",
"@types/nodemailer": "^6.4.8",
"mongodb-memory-server": "^10.1.4",
"ts-jest": "^29.4.4",
"tsconfig": "workspace:^",
"tsup": "^7.2.0",
"typescript": "^5.9.3",
Expand Down
52 changes: 52 additions & 0 deletions apps/queue/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import mongoose from "mongoose";
import { MongoMemoryServer } from "mongodb-memory-server";

let mongod: MongoMemoryServer | null = null;

// Suppress console.error during tests to reduce noise
const originalError = console.error;
beforeAll(() => {
console.error = jest.fn();
});

afterAll(() => {
console.error = originalError;
});

// Ensure MongoDB connection is established
// @shelf/jest-mongodb provides global.__MONGO_URI__ through globalSetup
// If not available, set up MongoDB Memory Server manually
beforeAll(async () => {
let mongoUri = (global as any).__MONGO_URI__ || process.env.MONGO_URL;

// If @shelf/jest-mongodb didn't set up MongoDB, do it manually
if (!mongoUri) {
mongod = await MongoMemoryServer.create();
mongoUri = mongod.getUri();
(global as any).__MONGO_URI__ = mongoUri;
}

if (mongoose.connection.readyState === 0) {
await mongoose.connect(mongoUri);
}
});

afterAll(async () => {
if (mongoose.connection.readyState !== 0) {
await mongoose.connection.close();
}

// Clean up manually created MongoDB instance if it exists
if (mongod) {
await mongod.stop();
}
});

// Clean up database after each test
export const cleanup = async () => {
const collections = mongoose.connection.collections;
for (const key in collections) {
const collection = collections[key];
await collection.deleteMany();
}
};
29 changes: 29 additions & 0 deletions apps/queue/src/__tests__/constants.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @jest-environment node
*/

import { sequenceBounceLimit } from "../constants";

describe("constants", () => {
it("should have a default sequenceBounceLimit of 3", () => {
expect(sequenceBounceLimit).toBeGreaterThanOrEqual(0);
});

it("should read sequenceBounceLimit from environment variable", () => {
const originalEnv = process.env.SEQUENCE_BOUNCE_LIMIT;

process.env.SEQUENCE_BOUNCE_LIMIT = "5";
// Note: This test demonstrates the pattern, but since the constant
// is evaluated at module load time, we'd need to reload the module
// to see the change. This is just for demonstration.

expect(sequenceBounceLimit).toBeDefined();

// Restore original value
if (originalEnv) {
process.env.SEQUENCE_BOUNCE_LIMIT = originalEnv;
} else {
delete process.env.SEQUENCE_BOUNCE_LIMIT;
}
});
});
Loading
Loading