用于多个测试的模拟 Multer(vitest 和 Typescript)

问题描述 投票:0回答:1

我想测试我的路线。问题是我不能用不同的内容多次模拟“multer”。我的测试:

import request from "supertest";
import express from "express";
import importRouter from "../routes/import.route"; // Deine Route importieren
import { vi, describe, it, expect, beforeEach } from "vitest";

let counter = 0;

beforeEach(() => {
  // Mocke multer und füge diskStorage statisch hinzu
  vi.mock("multer", () => {
    // Erstelle single und diskStorage innerhalb der Mock-Funktion
    const single = vi.fn(
      (fieldname: any) => (req: any, res: any, next: any) => {
        req.file = {
          originalname: "test.csv",
          size: counter === 2 ? 100 : 600 * 1024, // Simuliere Dateigröße
          path: "uploads/test.csv",
        };

        const error: any =
          counter === 2
            ? new Error("Unknown error")
            : new Error("File too large");
        error.code = counter === 2 ? "UNKNOWN_ERROR" : "LIMIT_FILE_SIZE";
        next(error); // Simuliere Dateigrößenfehler
      }
    );

    const diskStorage = vi.fn(() => ({
      destination: vi.fn((req, file, cb) => cb(null, "uploads")),
      filename: vi.fn((req, file, cb) => cb(null, file.originalname)),
    }));

    const multerMock = () => ({
      single,
      diskStorage: diskStorage(),
    });

    multerMock.diskStorage = diskStorage;

    return {
      default: multerMock,
      diskStorage,
    };
  });

  counter++;
});

describe("POST /import/customers", () => {
  it("should return 400 if file size exceeds limit (512KB)", async () => {
    let app = express();
    app.use(express.json());
    app.use("/import", importRouter);

    // Verwende Supertest, um die Route zu testen
    const res = await request(app)
      .post("/import/customers")
      .attach("file", Buffer.from("Some content"), "test.csv");

    expect(res.status).toBe(400);
    expect(res.body.msg).toBe("File too large. Maximum size is 512KB.");
  });

  it("should return 500 for general file upload error", async () => {
    let app = express();
    app.use(express.json());
    app.use("/import", importRouter);

    const res = await request(app)
      .post("/import/customers")
      .attach("file", Buffer.from("Some content"), "test.csv");

    expect(res.status).toBe(500);
    expect(res.body.msg).toBe("File upload error");
  });
});

文件:

import { Router } from "express";
import multer from "multer";
import { importCustomers } from "../controllers/import.controller";
import * as path from "path";

const router = Router();
// Multer configuration for file uploads
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    const uploadPath = path.resolve(__dirname, "..", "..", "uploads");
    cb(null, uploadPath);
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  },
});
const upload = multer({
  storage,
  limits: { fileSize: 512 * 1024 }, // 512KB in Bytes
}).single("file");

/**
 * @route POST /import/customers
 * @desc Import customers from a CSV file
 */
router.post(
  "/customers",
  (req, res, next) => {
    upload(req, res, (err) => {
      if (err) {
        if (err.code === "LIMIT_FILE_SIZE") {
          return res
            .status(400)
            .json({ msg: "File too large. Maximum size is 512KB." });
        }
        return res
          .status(500)
          .json({ msg: "File upload error", error: err.message });
      }
      next(); // Go to next controller
    });
  },
  importCustomers
);

export default router;

这个测试也有效。但我不想使用“计数器”值来处理 multer 函数的不同主体/内容。那么我怎样才能以通用的方式做到这一点呢?

node.js multer vitest
1个回答
0
投票

我相信,您可以使用模拟动态设置上下文。 注意:还没有测试过它,只是拿了我们在测试中使用的东西并应用了:

import request from "supertest";
import express from "express";
import importRouter from "../routes/import.route";
import { vi, describe, it, expect, beforeEach } from "vitest";

beforeEach(() => {
  // Reset mocks before each test
  vi.resetModules();

  // Mock multer
  vi.mock("multer", () => {
    const single = vi.fn(
      (fieldname: any) => (req: any, res: any, next: any) => {
        req.file = {
          originalname: "test.csv",
          size: 600 * 1024, // Default size
          path: "uploads/test.csv",
        };

        // Check if a custom error is set on the request object for testing purposes
        if (req.mockError) {
          const error: any = new Error(req.mockError.message);
          error.code = req.mockError.code;
          return next(error);
        }

        next();
      }
    );

    const diskStorage = vi.fn(() => ({
      destination: vi.fn((req, file, cb) => cb(null, "uploads")),
      filename: vi.fn((req, file, cb) => cb(null, file.originalname)),
    }));

    const multerMock = () => ({
      single,
      diskStorage: diskStorage(),
    });

    multerMock.diskStorage = diskStorage;

    return {
      default: multerMock,
      diskStorage,
    };
  });
});

describe("POST /import/customers", () => {
  it("should return 400 if file size exceeds limit (512KB)", async () => {
    let app = express();
    app.use(express.json());
    app.use("/import", importRouter);

    // Mock a file size limit error for this test case
    const res = await request(app)
      .post("/import/customers")
      .attach("file", Buffer.from("Some content"), "test.csv")
      .set("mock-error-code", "LIMIT_FILE_SIZE")
      .set("mock-error-message", "File too large");

    expect(res.status).toBe(400);
    expect(res.body.msg).toBe("File too large. Maximum size is 512KB.");
  });

  it("should return 500 for general file upload error", async () => {
    let app = express();
    app.use(express.json());
    app.use("/import", importRouter);

    // Mock a general error for this test case
    const res = await request(app)
      .post("/import/customers")
      .attach("file", Buffer.from("Some content"), "test.csv")
      .set("mock-error-code", "UNKNOWN_ERROR")
      .set("mock-error-message", "Unknown error");

    expect(res.status).toBe(500);
    expect(res.body.msg).toBe("File upload error");
  });
});
© www.soinside.com 2019 - 2024. All rights reserved.