2026-08-01 13:26:23 +01:00

144 lines
3.8 KiB
JavaScript

import { jest } from '@jest/globals';
import express from 'express';
import request from 'supertest';
const printerId = '507f1f77bcf86cd799439011';
const storedFileId = '507f1f77bcf86cd799439012';
const printer = { _id: printerId, pendingSlicerUploads: [] };
const findById = jest.fn(() => ({
select: jest.fn(() => ({
lean: jest.fn().mockResolvedValue(printer),
})),
}));
const newObject = jest.fn();
const editObject = jest.fn();
const deleteObject = jest.fn();
const uploadFile = jest.fn();
const deleteFile = jest.fn();
const getFileMeta = jest.fn();
jest.unstable_mockModule('../../../config.js', () => ({
default: {
server: { logLevel: 'info' },
app: { urlClient: 'http://localhost:3000' },
},
}));
jest.unstable_mockModule('../../../database/schemas/management/file.schema.js', () => ({
fileModel: { modelName: 'file' },
}));
jest.unstable_mockModule('../../../database/schemas/production/printer.schema.js', () => ({
printerModel: { modelName: 'printer', findById },
}));
jest.unstable_mockModule('../../../database/database.js', () => ({
getPropertyValues: jest.fn(),
deleteObject,
editObject,
newObject,
getObjectNeighbors: jest.fn(),
}));
jest.unstable_mockModule('../../../database/ceph.js', () => ({
BUCKETS: { FILES: 'files' },
deleteFile,
uploadFile,
}));
jest.unstable_mockModule('../../../utils.js', () => ({
getFileMeta,
}));
jest.unstable_mockModule('../sessionStore.js', () => ({
createSlicerAuthCode: jest.fn(),
createSlicerSession: jest.fn(),
}));
jest.unstable_mockModule('log4js', () => ({
default: {
getLogger: () => ({
level: 'info',
debug: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
}),
},
}));
const { slicerUploadRouteHandler } = await import('../slicer.js');
describe('slicer upload', () => {
beforeEach(() => {
jest.clearAllMocks();
newObject.mockResolvedValue({ _id: storedFileId });
editObject.mockResolvedValue({ _id: printerId });
getFileMeta.mockResolvedValue({ generator: 'test-slicer' });
});
it('stores the multipart file bytes and parses OctoPrint boolean fields', async () => {
const app = express();
app.post(
'/slicer/:printerId/user/pass/api/files/local',
(req, _res, next) => {
req.user = { username: 'slicer-user' };
next();
},
slicerUploadRouteHandler
);
const fileContents = Buffer.from('G28\nG1 X10 Y20\n');
const response = await request(app)
.post(`/slicer/${printerId}/user/pass/api/files/local`)
.field('select', 'true')
.field('print', 'false')
.attach('file', fileContents, {
filename: 'part.gcode',
// Cura and other slicers may identify G-code as compressible text.
contentType: 'text/plain',
});
expect(response.status).toBe(201);
expect(uploadFile).toHaveBeenCalledWith(
'files',
`files/${storedFileId}.gcode`,
fileContents,
'application/octet-stream',
{
originalName: 'part.gcode',
uploadedBy: 'slicer-user',
}
);
expect(newObject).toHaveBeenCalledWith(
expect.objectContaining({
newData: expect.objectContaining({
name: 'part',
extension: '.gcode',
size: fileContents.length,
}),
})
);
expect(editObject).toHaveBeenCalledWith(
expect.objectContaining({
updateData: {
pendingSlicerUploads: [
expect.objectContaining({
file: { _id: storedFileId },
shouldPrint: false,
}),
],
},
})
);
expect(response.body).toEqual(
expect.objectContaining({
done: true,
effectiveSelect: true,
effectivePrint: false,
})
);
expect(response.headers.location).toMatch(/\/part\.gcode$/);
});
});