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$/); }); });