'use strict'; /** * Integration tests – geoitem controller (controllers/geoitem.js) */ const mongoose = require('mongoose'); const { connectDB, disconnectDB, clearCollection } = require('./jest.setup'); const { mockApplicator, mockClient, mockReq, mockRes, newId } = require('./mock_data'); let Area, Customer, Client; beforeAll(async () => { await connectDB(); Area = require('../../model/area'); Customer = require('../../model/customer'); Client = require('../../model/client'); }); afterAll(async () => { await disconnectDB(); }); const geoitemCtl = require('../../controllers/geoitem'); /** Minimal valid GeoJSON Polygon coordinates (a small square) */ function squareCoords() { return [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]]; } function mockArea(clientId, overrides = {}) { return { properties: { name: `Area-${Date.now()}`, type: 0, color: '#FF0000', area: 1.5, }, geometry: { type: 'Polygon', coordinates: squareCoords(), }, client: clientId, ...overrides, }; } describe('geoitem controller – data methods', () => { let applicator, client; beforeAll(async () => { await clearCollection(Area); applicator = await Customer.create(mockApplicator()); client = await Client.create(mockClient(applicator._id)); }); afterAll(async () => { await clearCollection(Area); await Customer.deleteMany({ _id: { $in: [applicator._id, client._id] } }); }); const makeReq = (extra = {}) => mockReq({ uid: applicator._id, puid: applicator._id, ut: '1', ...extra }); // ------------------------------------------------------------------------- describe('findAreas_post', () => { it('throws when clientId is missing from body', async () => { const req = makeReq({ body: {} }); const res = mockRes(); await expect(geoitemCtl.findAreas_post(req, res)).rejects.toThrow(); }); it('throws when clientId is not a valid ObjectId', async () => { const req = makeReq({ body: { clientId: 'not-an-id' } }); const res = mockRes(); await expect(geoitemCtl.findAreas_post(req, res)).rejects.toThrow(); }); it('returns an empty array when no areas exist for the client', async () => { const req = makeReq({ body: { clientId: client._id.toHexString() } }); const res = mockRes(); await geoitemCtl.findAreas_post(req, res); expect(res.json).toHaveBeenCalled(); expect(Array.isArray(res._data)).toBe(true); expect(res._data.length).toBe(0); }); it('returns areas belonging to the specified client', async () => { await Area.create(mockArea(client._id)); await Area.create(mockArea(client._id)); const req = makeReq({ body: { clientId: client._id.toHexString() } }); const res = mockRes(); await geoitemCtl.findAreas_post(req, res); expect(res.json).toHaveBeenCalled(); expect(res._data.length).toBe(2); // toGeoItems output shape: { _id, properties, geometry, client } expect(res._data[0]).toHaveProperty('_id'); expect(res._data[0]).toHaveProperty('geometry'); }); it('does not return areas belonging to a different client', async () => { const otherClient = await Client.create(mockClient(applicator._id)); await Area.create(mockArea(otherClient._id)); const req = makeReq({ body: { clientId: client._id.toHexString() } }); const res = mockRes(); await geoitemCtl.findAreas_post(req, res); expect(res.json).toHaveBeenCalled(); // Should still only see 2 (created in previous test) const clientIds = res._data.map(f => String(f.properties?.client ?? '')); expect(clientIds.every(id => id !== String(otherClient._id) || id === '')).toBe(true); await Client.deleteMany({ _id: otherClient._id }); }); }); // ------------------------------------------------------------------------- describe('update_post', () => { it('returns immediately when all update arrays are empty', async () => { const req = makeReq({ body: { c: [], u: [], r: [] } }); const res = mockRes(); await geoitemCtl.update_post(req, res); expect(res.end).toHaveBeenCalled(); }); it('returns immediately when body is null', async () => { const req = makeReq({ body: null }); const res = mockRes(); await geoitemCtl.update_post(req, res); expect(res.end).toHaveBeenCalled(); }); it('inserts new areas via the c (create) array', async () => { const area = mockArea(client._id); const req = makeReq({ body: { c: [area] } }); const res = mockRes(); await geoitemCtl.update_post(req, res); expect(res.json).toHaveBeenCalled(); expect(res._data).toEqual({ ok: true }); const found = await Area.find({ client: client._id }); expect(found.length).toBeGreaterThan(0); }); it('removes areas via the r (remove) array', async () => { const doc = await Area.create(mockArea(client._id)); const countBefore = await Area.countDocuments({ client: client._id }); const req = makeReq({ body: { r: [String(doc._id)] } }); const res = mockRes(); await geoitemCtl.update_post(req, res); expect(res.json).toHaveBeenCalled(); expect(res._data).toEqual({ ok: true }); const countAfter = await Area.countDocuments({ client: client._id }); expect(countAfter).toBe(countBefore - 1); }); }); // ------------------------------------------------------------------------- describe('addToLibrary_post', () => { it('throws when areas array is empty', async () => { const req = makeReq({ body: { areas: [] } }); const res = mockRes(); await expect(geoitemCtl.addToLibrary_post(req, res)).rejects.toThrow(); }); it('throws when body has no areas field', async () => { const req = makeReq({ body: {} }); const res = mockRes(); await expect(geoitemCtl.addToLibrary_post(req, res)).rejects.toThrow(); }); }); });