Some checks failed
farmcontrol/farmcontrol-api/pipeline/head There was a failure building this commit
This commit introduces new schemas and routes for managing email accounts, email messages, and email templates. It adds functionality for CRUD operations on these entities, including listing, searching, and retrieving properties. The email message handling is enhanced with a worker for asynchronous email delivery, and the audit log schema is updated to accommodate system actions. Additionally, utility functions are improved for better data handling and validation. These changes significantly enhance the application's email management capabilities.
171 lines
4.8 KiB
JavaScript
171 lines
4.8 KiB
JavaScript
import { jest } from '@jest/globals';
|
|
|
|
jest.unstable_mockModule('../../../database/schemas/management/emailtemplate.schema.js', () => ({
|
|
emailTemplateModel: { modelName: 'emailTemplate' },
|
|
}));
|
|
jest.unstable_mockModule('../../../database/database.js', () => ({
|
|
deleteObject: jest.fn(),
|
|
editObject: jest.fn(),
|
|
getObject: jest.fn(),
|
|
getModelHistory: jest.fn(),
|
|
getModelStats: jest.fn(),
|
|
getObjectNeighbors: jest.fn(),
|
|
getPropertyValues: jest.fn(),
|
|
listObjects: jest.fn(),
|
|
listObjectsByProperties: jest.fn(),
|
|
newObject: jest.fn(),
|
|
searchObjects: jest.fn(),
|
|
}));
|
|
jest.unstable_mockModule('../../../templates/templatemanager.js', () => ({
|
|
templateManager: { renderEmailTemplate: jest.fn() },
|
|
}));
|
|
jest.unstable_mockModule('../../../templates/templateformatter.js', () => ({
|
|
formatTemplateContent: jest.fn((content) => ({ content })),
|
|
}));
|
|
jest.unstable_mockModule('log4js', () => ({
|
|
default: {
|
|
getLogger: () => ({
|
|
level: 'info',
|
|
debug: jest.fn(),
|
|
error: jest.fn(),
|
|
warn: jest.fn(),
|
|
trace: jest.fn(),
|
|
}),
|
|
},
|
|
}));
|
|
|
|
const {
|
|
editEmailTemplateRouteHandler,
|
|
getEmailTemplateNeighborsRouteHandler,
|
|
getEmailTemplateStatsRouteHandler,
|
|
listEmailTemplatesByPropertiesRouteHandler,
|
|
newEmailTemplateRouteHandler,
|
|
} = await import('../emailtemplates.js');
|
|
const { editObject, getModelStats, getObjectNeighbors, listObjectsByProperties, newObject } =
|
|
await import('../../../database/database.js');
|
|
|
|
const ATTACHMENT_POPULATE = { path: 'attachments.file', strictPopulate: false };
|
|
|
|
describe('email template standard handlers', () => {
|
|
let req;
|
|
let res;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
req = { query: {}, params: {}, body: {}, user: { _id: 'user-1' } };
|
|
res = { send: jest.fn(), status: jest.fn().mockReturnThis() };
|
|
});
|
|
|
|
it('supports active property lists and parent population', async () => {
|
|
listObjectsByProperties.mockResolvedValue([{ name: 'Invoice', active: true }]);
|
|
await listEmailTemplatesByPropertiesRouteHandler(
|
|
req,
|
|
res,
|
|
['name', 'active'],
|
|
{ active: true },
|
|
{}
|
|
);
|
|
|
|
expect(listObjectsByProperties).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
properties: ['name', 'active'],
|
|
filter: { active: true },
|
|
populate: [
|
|
{ path: 'parent', strictPopulate: false },
|
|
ATTACHMENT_POPULATE,
|
|
],
|
|
})
|
|
);
|
|
});
|
|
|
|
it('returns stats and neighbors through generic database helpers', async () => {
|
|
getModelStats.mockResolvedValue({ count: 2 });
|
|
getObjectNeighbors.mockResolvedValue({ previous: null, next: 'template-2' });
|
|
|
|
await getEmailTemplateStatsRouteHandler(req, res);
|
|
await getEmailTemplateNeighborsRouteHandler(
|
|
req,
|
|
res,
|
|
'',
|
|
{ active: true },
|
|
'',
|
|
'name',
|
|
'ascend',
|
|
'template-1'
|
|
);
|
|
|
|
expect(getModelStats).toHaveBeenCalled();
|
|
expect(getObjectNeighbors).toHaveBeenCalledWith(
|
|
expect.objectContaining({ id: 'template-1', filter: { active: true }, sort: 'name' })
|
|
);
|
|
});
|
|
|
|
it('persists normalized attachments on create and edit', async () => {
|
|
const attachments = [
|
|
{
|
|
type: 'documentTemplate',
|
|
file: { _id: 'doc-1' },
|
|
fileName: 'Invoice',
|
|
fileType: 'pdf',
|
|
},
|
|
{
|
|
type: 'file',
|
|
file: 'file-1',
|
|
fileName: 'Terms',
|
|
},
|
|
];
|
|
req.body = { name: 'Invoice', attachments };
|
|
newObject.mockResolvedValue({ _id: 'template-1' });
|
|
editObject.mockResolvedValue({ _id: 'template-1' });
|
|
|
|
await newEmailTemplateRouteHandler(req, res);
|
|
|
|
expect(newObject).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
newData: expect.objectContaining({
|
|
attachments: [
|
|
{
|
|
_id: undefined,
|
|
type: 'documentTemplate',
|
|
file: 'doc-1',
|
|
fileName: 'Invoice',
|
|
fileType: 'pdf',
|
|
},
|
|
{
|
|
_id: undefined,
|
|
type: 'file',
|
|
file: 'file-1',
|
|
fileName: 'Terms',
|
|
fileType: undefined,
|
|
},
|
|
],
|
|
}),
|
|
})
|
|
);
|
|
|
|
req.params = { id: '507f1f77bcf86cd799439011' };
|
|
await editEmailTemplateRouteHandler(req, res);
|
|
|
|
expect(editObject).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
updateData: expect.objectContaining({
|
|
attachments: [
|
|
expect.objectContaining({
|
|
type: 'documentTemplate',
|
|
file: 'doc-1',
|
|
fileName: 'Invoice',
|
|
fileType: 'pdf',
|
|
}),
|
|
expect.objectContaining({
|
|
type: 'file',
|
|
file: 'file-1',
|
|
fileName: 'Terms',
|
|
}),
|
|
],
|
|
}),
|
|
populate: expect.arrayContaining([ATTACHMENT_POPULATE]),
|
|
})
|
|
);
|
|
});
|
|
});
|