test/unit/api/v2/assets/assets.controller.spec.tsmodifiedimport sinon from "sinon";
import * as chai from "chai";
import chaiAsPromised from "chai-as-promised";
import sinonChai from "sinon-chai";
import { mockRequest, mockResponse, RequestOutput, ResponseOutput } from "mock-req-res";
import * as service from "../../../../../src/services/assets.service";
import * as controller from "../../../../../src/api/v2/projects/assets/assets.controller";
import { NotFoundError } from "../../../../../src/types/errortypes";
import { Asset } from "../../../../../src/services/assets.service";
chai.use(chaiAsPromised).use(sinonChai);
chai.should();
const expect = chai.expect;
/* eslint-disable @typescript-eslint/no-explicit-any */
describe("Assets Controller", () => {
let req: RequestOutput;
let res: ResponseOutput;
const projectId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
const assetId = "11111111-2222-3333-4444-555555555555";
const assetTypeId = "cccccccc-dddd-eeee-ffff-aaaaaaaaaaaa";
const sampleAsset: Asset = {
assetId,
name: "Chiller Unit 1",
assetTypeId,
createdBy: "user@example.com",
insertedOn: new Date("2025-01-01T00:00:00Z"),
lastModifiedOn: null,
lastModifiedBy: null,
};
beforeEach(() => {
res = mockResponse();
});
afterEach(() => {
sinon.restore();
});
describe("listAssets", () => {
it("should return 200 with a paginated envelope of assets", async () => {
req = mockRequest({ params: { projectId }, query: {} });
sinon.stub(service, "listAssets").resolves([{ ...sampleAsset, indexId: 42 }]);
await controller.listAssets(req as any, res as any);
expect(res.status).to.have.been.calledWith(200);
expect(res.json).to.have.been.calledWith({
records: [sampleAsset],
recordCount: 1,
lastFetchedIndexId: 42,
});
});
it("should forward paging query params to the service", async () => {
req = mockRequest({ params: { projectId }, query: { lastFetchedIndexId: "42", size: "5" } });
const listStub = sinon.stub(service, "listAssets").resolves([]);
await controller.listAssets(req as any, res as any);
expect(listStub).to.have.been.calledWith(
projectId,
sinon.match({ lastFetchedIndexId: 42, size: 5 }),
);
expect(res.status).to.have.been.calledWith(200);
expect(res.json).to.have.been.calledWith({
records: [],
recordCount: 0,
lastFetchedIndexId: -1,
});
});
it("should return 500 on unexpected error", async () => {
req = mockRequest({ params: { projectId }, query: {} });
sinon.stub(service, "listAssets").throws(new Error("DB error"));
await controller.listAssets(req as any, res as any);
expect(res.status).to.have.been.calledWith(500);
});
});
describe("getAsset", () => {
it("should return 200 with the asset", async () => {
req = mockRequest({ params: { projectId, assetId } });
sinon.stub(service, "getAssetById").resolves(sampleAsset);
await controller.getAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(200);
expect(res.json).to.have.been.calledWith(sampleAsset);
});
it("should return 404 when asset not found", async () => {
req = mockRequest({ params: { projectId, assetId } });
sinon.stub(service, "getAssetById").throws(new NotFoundError("Not found"));
await controller.getAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(404);
});
});
describe("createAsset", () => {
it("should return 201 with the created asset", async () => {
req = mockRequest({ params: { projectId }, body: { name: "Chiller Unit 1", assetTypeId } });
sinon.stub(service, "createAsset").resolves(sampleAsset);
await controller.createAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(201);
expect(res.json).to.have.been.calledWith(sampleAsset);
});
it("should return 404 when asset type not found", async () => {
req = mockRequest({ params: { projectId }, body: { name: "Chiller Unit 1", assetTypeId } });
sinon.stub(service, "createAsset").throws(new NotFoundError("AssetType with id not found"));
await controller.createAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(404);
});
it("should return 500 on unexpected error", async () => {
req = mockRequest({ params: { projectId }, body: { name: "Chiller Unit 1", assetTypeId } });
sinon.stub(service, "createAsset").throws(new Error("DB error"));
await controller.createAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(500);
});
});
describe("patchAsset", () => {
it("should return 200 with the updated asset", async () => {
const updatedAsset: Asset = { ...sampleAsset, name: "Chiller Unit 2", lastModifiedBy: "user@example.com", lastModifiedOn: new Date("2026-07-10T00:00:00Z") };
req = mockRequest({ params: { projectId, assetId }, body: { name: "Chiller Unit 2" } });
const updateStub = sinon.stub(service, "updateAsset").resolves(updatedAsset);
await controller.patchAsset(req as any, res as any);
expect(updateStub).to.have.been.calledWith(projectId, assetId, sinon.match({ name: "Chiller Unit 2" }));
expect(res.status).to.have.been.calledWith(200);
expect(res.json).to.have.been.calledWith(updatedAsset);
});
it("should forward only the name to the service (relational fields are out of scope)", async () => {
const parentAssetId = "22222222-3333-4444-8555-666666666666";
const updatedAsset: Asset = { ...sampleAsset, name: "Chiller Unit 2", lastModifiedBy: "user@example.com", lastModifiedOn: new Date("2026-07-10T00:00:00Z") };
req = mockRequest({ params: { projectId, assetId }, body: { name: "Chiller Unit 2", assetTypeId, parentAssetId } });
const updateStub = sinon.stub(service, "updateAsset").resolves(updatedAsset);
await controller.patchAsset(req as any, res as any);
const patchArg = updateStub.firstCall.args[2];
expect(patchArg).to.deep.equal({ name: "Chiller Unit 2" });
expect(patchArg).to.not.have.property("assetTypeId");
expect(patchArg).to.not.have.property("parentAssetId");
expect(res.status).to.have.been.calledWith(200);
expect(res.json).to.have.been.calledWith(updatedAsset);
});
it("should return 404 when asset not found", async () => {
req = mockRequest({ params: { projectId, assetId }, body: { name: "Chiller Unit 2" } });
sinon.stub(service, "updateAsset").throws(new NotFoundError("Not found"));
await controller.patchAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(404);
});
it("should return 500 on unexpected error", async () => {
req = mockRequest({ params: { projectId, assetId }, body: { name: "Chiller Unit 2" } });
sinon.stub(service, "updateAsset").throws(new Error("DB error"));
await controller.patchAsset(req as any, res as any);
expect(res.status).to.have.been.calledWith(500);
});
});
});