agmission/Development/server/tests/integration/api_pub.integration.test.js
2026-04-29 09:40:51 -04:00

199 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
/**
* Integration tests api_pub controller (controllers/api_pub.js)
*/
const { connectDB, disconnectDB, clearCollection } = require('./jest.setup');
const { mockApplicator, mockClient, mockJob, mockReq, mockRes } = require('./mock_data');
let Job, App, AppFile, Customer, Client;
beforeAll(async () => {
await connectDB();
({ Job, App, AppFile } = require('../../model'));
Customer = require('../../model/customer');
Client = require('../../model/client');
});
afterAll(async () => {
await disconnectDB();
});
const apiPubCtl = require('../../controllers/api_pub');
/** Generate a unique integer job id that won't collide across tests */
let _nextJobId = 900001;
function nextJobId() { return _nextJobId++; }
describe('api_pub controller', () => {
let applicator, client, jobRecord;
beforeAll(async () => {
await clearCollection(Job);
await clearCollection(App);
await clearCollection(AppFile);
applicator = await Customer.create(mockApplicator());
client = await Client.create(mockClient(applicator._id));
const jobId = nextJobId();
jobRecord = await Job.create(
mockJob(applicator._id, {
_id: jobId,
client: client._id,
})
);
});
afterAll(async () => {
await clearCollection(Job);
await clearCollection(App);
await clearCollection(AppFile);
await Customer.deleteMany({ _id: { $in: [applicator._id, client._id] } });
});
const makeReq = (extra = {}) =>
mockReq({ uid: applicator._id, puid: applicator._id, ut: '1', ...extra });
// -------------------------------------------------------------------------
describe('getSessions', () => {
it('throws AppParamError when jobId is not a number', async () => {
const req = makeReq({ params: { jobId: 'not-a-number' } });
const res = mockRes();
await expect(apiPubCtl.getSessions(req, res)).rejects.toThrow();
});
it('throws JOB_NOT_FOUND for a job that does not exist', async () => {
const req = makeReq({ params: { jobId: '999999' } });
const res = mockRes();
await expect(apiPubCtl.getSessions(req, res)).rejects.toThrow();
});
it('throws AppAuthError when uid does not own the job', async () => {
const other = await Customer.create(mockApplicator());
const req = mockReq({
uid: other._id,
puid: other._id,
params: { jobId: String(jobRecord._id) },
});
const res = mockRes();
await expect(apiPubCtl.getSessions(req, res)).rejects.toThrow();
await Customer.deleteMany({ _id: other._id });
});
it('returns empty data array when job has no apps', async () => {
const req = makeReq({ params: { jobId: String(jobRecord._id) } });
const res = mockRes();
await apiPubCtl.getSessions(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.jobId).toBe(jobRecord._id);
expect(res._data.data).toEqual([]);
});
it('returns sessions when apps exist for the job', async () => {
const app = await App.create({
_id: require('mongoose').Types.ObjectId(),
jobId: jobRecord._id,
fileName: 'testflight.agn',
fileSize: 0,
markedDelete: false,
});
const req = makeReq({ params: { jobId: String(jobRecord._id) } });
const res = mockRes();
await apiPubCtl.getSessions(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.data.length).toBe(1);
expect(String(res._data.data[0].sessionId)).toBe(String(app._id));
await App.deleteMany({ _id: app._id });
});
});
// -------------------------------------------------------------------------
describe('getAreas', () => {
it('throws when jobId is not a number', async () => {
const req = makeReq({ params: { jobId: 'abc' } });
const res = mockRes();
await expect(apiPubCtl.getAreas(req, res)).rejects.toThrow();
});
it('throws JOB_NOT_FOUND when job does not exist', async () => {
const req = makeReq({ params: { jobId: '999998' } });
const res = mockRes();
await expect(apiPubCtl.getAreas(req, res)).rejects.toThrow();
});
it('returns a GeoJSON FeatureCollection with empty features when job has no areas', async () => {
const req = makeReq({ params: { jobId: String(jobRecord._id) } });
const res = mockRes();
await apiPubCtl.getAreas(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.type).toBe('FeatureCollection');
expect(Array.isArray(res._data.features)).toBe(true);
expect(res._data.features.length).toBe(0);
});
it('returns area features when sprayAreas are defined on the job', async () => {
const area = {
properties: { name: 'Block A', area: 2.5 },
geometry: {
type: 'Polygon',
coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]],
},
};
await Job.findByIdAndUpdate(jobRecord._id, { sprayAreas: [area] });
const req = makeReq({ params: { jobId: String(jobRecord._id) } });
const res = mockRes();
await apiPubCtl.getAreas(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.features.length).toBe(1);
expect(res._data.features[0].properties.name).toBe('Block A');
// Cleanup
await Job.findByIdAndUpdate(jobRecord._id, { sprayAreas: [] });
});
});
// -------------------------------------------------------------------------
describe('getSessionRecords', () => {
it('throws when jobId is not a number', async () => {
const mongoose = require('mongoose');
const req = makeReq({
params: { jobId: 'abc', fileId: new mongoose.Types.ObjectId().toHexString() },
});
const res = mockRes();
await expect(apiPubCtl.getSessionRecords(req, res)).rejects.toThrow();
});
it('throws when fileId is not a valid ObjectId', async () => {
const req = makeReq({
params: { jobId: String(jobRecord._id), fileId: 'invalid' },
});
const res = mockRes();
await expect(apiPubCtl.getSessionRecords(req, res)).rejects.toThrow();
});
it('throws NOT_FOUND when AppFile does not exist', async () => {
const mongoose = require('mongoose');
const req = makeReq({
params: {
jobId: String(jobRecord._id),
fileId: new mongoose.Types.ObjectId().toHexString(),
},
});
const res = mockRes();
await expect(apiPubCtl.getSessionRecords(req, res)).rejects.toThrow();
});
});
});