agmission/Development/server/tests/integration/job.integration.test.js
Devin Major 6ff07c9d74
All checks were successful
Server Tests / Mocha – Unit & Utility Tests (push) Successful in 1m13s
Server Tests / Jest – Integration Tests (push) Successful in 1m43s
additional integration tests
2026-05-08 14:51:04 -04:00

589 lines
19 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 job controller (controllers/job.js)
*
* The job controller is a factory: require('../../controllers/job')({})
* Job._id is an auto-increment numeric field.
* deleteJob wraps transaction errors with try/catch so it works on
* standalone MongoDB (no replica-set needed).
*/
const { connectDB, disconnectDB, clearCollection } = require('./jest.setup');
const {
mockApplicator,
mockClient,
mockPilot,
mockVehicle,
mockJob,
mockReq,
mockRes,
newId,
} = require('./mock_data');
let Job, Customer, Client, Pilot, Vehicle;
beforeAll(async () => {
await connectDB();
Customer = require('../../model/customer');
Client = require('../../model/client');
Pilot = require('../../model/pilot');
Vehicle = require('../../model/vehicle');
Job = require('../../model/job');
});
afterAll(async () => {
await disconnectDB();
});
// Job controller is a factory
const jobCtl = require('../../controllers/job')({});
describe('job controller data methods', () => {
let applicator, client, pilot, vehicle;
beforeAll(async () => {
await clearCollection(Job);
applicator = await Customer.create(mockApplicator());
client = await Client.create(mockClient(applicator._id));
pilot = await Pilot.create(mockPilot(applicator._id));
vehicle = await Vehicle.create(mockVehicle(applicator._id));
});
afterAll(async () => {
await clearCollection(Job);
await Client.deleteMany({ _id: client._id });
await Pilot.deleteMany({ _id: pilot._id });
await Vehicle.deleteMany({ _id: vehicle._id });
await Customer.deleteMany({ _id: applicator._id });
});
const makeReq = (extra = {}) =>
mockReq({
uid: applicator._id,
puid: applicator._id,
ut: '1',
userInfo: {
puid: applicator._id,
kind: '1',
premium: 0,
membership: null,
markedDelete: false,
},
...extra,
});
// -------------------------------------------------------------------------
describe('createJob_post', () => {
it('creates a job and returns it', async () => {
const body = mockJob(applicator._id);
body.client = client._id;
body.pilot = pilot._id;
body.vehicle = vehicle._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data._id).toBeDefined();
expect(typeof res._data._id).toBe('number');
});
it('throws when puid is missing', async () => {
const req = makeReq({ puid: undefined, body: mockJob(applicator._id) });
const res = mockRes();
await expect(jobCtl.createJob_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('getJobs_get', () => {
it('returns jobs for the applicator', async () => {
const req = makeReq({ query: {} });
const res = mockRes();
await jobCtl.getJobs_get(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
expect(res._data.length).toBeGreaterThan(0);
});
it('returns empty array when puid has no jobs', async () => {
const unknownId = newId();
const req = mockReq({
uid: unknownId,
puid: unknownId,
ut: '1',
userInfo: { puid: unknownId, kind: '1', premium: 0, membership: null, markedDelete: false },
query: {},
});
const res = mockRes();
await jobCtl.getJobs_get(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.length).toBe(0);
});
});
// -------------------------------------------------------------------------
describe('getJob_get', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
body.pilot = pilot._id;
body.vehicle = vehicle._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns a job by numeric id', async () => {
const req = makeReq({ params: { job_id: String(jobId) } });
const res = mockRes();
await jobCtl.getJob_get(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data._id).toBe(jobId);
});
});
// -------------------------------------------------------------------------
describe('updateJob_put', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
body.pilot = pilot._id;
body.vehicle = vehicle._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('updates a job field', async () => {
const req = makeReq({
params: { job_id: String(jobId) },
body: { job: { name: 'Updated Job Name' } },
});
const res = mockRes();
await jobCtl.updateJob_put(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.name).toBe('Updated Job Name');
});
});
// -------------------------------------------------------------------------
describe('deleteJob', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
body.pilot = pilot._id;
body.vehicle = vehicle._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('deletes a job (transaction error handled on standalone MongoDB)', async () => {
const req = makeReq({ params: { id: String(jobId) } });
const res = mockRes();
// deleteJob wraps the transaction with try/catch it either succeeds
// fully or returns a soft-success; either way res.json is called.
await jobCtl.deleteJob(req, res);
expect(res.json).toHaveBeenCalled();
});
});
// -------------------------------------------------------------------------
describe('getData_post', () => {
it('throws when jobId is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.getData_post(req, res)).rejects.toThrow();
});
it('returns data for a valid job id', async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const createReq = makeReq({ body });
const createRes = mockRes();
await jobCtl.createJob_post(createReq, createRes);
const jobId = createRes._data._id;
const req = makeReq({ body: { jobId } });
const res = mockRes();
await jobCtl.getData_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data).toBeTruthy();
});
});
// -------------------------------------------------------------------------
describe('getReportOps_get', () => {
it('returns null when jobId is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await jobCtl.getReportOps_get(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data).toBeNull();
});
});
// -------------------------------------------------------------------------
describe('preAppReport_post', () => {
it('throws when job is not found', async () => {
const req = makeReq({ body: { jobId: 99999999 } });
const res = mockRes();
await expect(jobCtl.preAppReport_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('getRptVars_post', () => {
it('returns null when no vars exist for the given rpt', async () => {
const req = makeReq({ body: { rpt: `test_rpt_${Date.now()}` } });
const res = mockRes();
await jobCtl.getRptVars_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data).toBeNull();
});
});
// -------------------------------------------------------------------------
describe('setRptVars_post', () => {
it('throws when rpt is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.setRptVars_post(req, res)).rejects.toThrow();
});
it('saves report vars when rpt is provided', async () => {
const req = makeReq({ body: { rpt: 'test_rpt', vars: { foo: 'bar' } } });
const res = mockRes();
await jobCtl.setRptVars_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data.ok).toBe(true);
});
});
// -------------------------------------------------------------------------
describe('saveReport_post', () => {
it('throws or handles missing REPORT_DIR gracefully', async () => {
// saveReport_post writes to env.REPORT_DIR in test it may not exist, so we test that the call happens
const req = makeReq({ body: { rid: 'test_report_id', content: '<report/>' } });
const res = mockRes();
// Either saves successfully (REPORT_DIR exists) or throws (REPORT_DIR missing)
try {
await jobCtl.saveReport_post(req, res);
expect(res.json).toHaveBeenCalled();
} catch (_err) {
// Expected in CI without REPORT_DIR configured
expect(_err).toBeDefined();
}
});
});
// -------------------------------------------------------------------------
describe('preLoadReport_post', () => {
it('calls next with error when jobId is missing from body', (done) => {
const req = makeReq({ body: {} });
const res = mockRes();
const next = (err) => {
expect(err).toBeDefined();
done();
};
jobCtl.preLoadReport_post(req, res, next);
});
});
// -------------------------------------------------------------------------
describe('getUploadedFiles_post', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns empty array of uploaded files for a valid job', async () => {
const req = makeReq({ body: { jobId } });
const res = mockRes();
await jobCtl.getUploadedFiles_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
});
});
// -------------------------------------------------------------------------
describe('importStatus_post', () => {
it('throws when appId is not a valid ObjectId', async () => {
const req = makeReq({ body: { appId: 'invalid-id' } });
const res = mockRes();
await expect(jobCtl.importStatus_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('importingStatus_post', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns empty array for a valid jobId with no importing files', async () => {
const req = makeReq({ body: { jobId } });
const res = mockRes();
await jobCtl.importingStatus_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
});
});
// -------------------------------------------------------------------------
describe('deleteAppFile_post', () => {
it('responds after calling delete (even with invalid appId)', async () => {
const req = makeReq({ body: { appId: String(newId()) } });
const res = mockRes();
await jobCtl.deleteAppFile_post(req, res);
expect(res.json).toHaveBeenCalled();
});
});
// -------------------------------------------------------------------------
describe('getJobLogs_post', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns empty array of logs for a new job', async () => {
const req = makeReq({ body: { jobId } });
const res = mockRes();
await jobCtl.getJobLogs_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
});
});
// -------------------------------------------------------------------------
describe('assign_post', () => {
it('throws when required params are missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.assign_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('assignments_post', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns { avUsers, asUsers } for a valid job', async () => {
const req = makeReq({ body: { jobId } });
const res = mockRes();
await jobCtl.assignments_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(res._data).toHaveProperty('avUsers');
expect(res._data).toHaveProperty('asUsers');
});
it('throws when jobId is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.assignments_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('countByClient_post', () => {
it('returns the job count for a client', async () => {
const req = makeReq({ body: { clientId: String(client._id) } });
const res = mockRes();
await jobCtl.countByClient_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(typeof res._data).toBe('number');
});
it('throws when clientId is invalid', async () => {
const req = makeReq({ body: { clientId: 'bad-id' } });
const res = mockRes();
await expect(jobCtl.countByClient_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('saveMapOps_post', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('throws when mapOps params are missing', async () => {
const req = makeReq({ body: { jobId, mapOps: {} } });
const res = mockRes();
await expect(jobCtl.saveMapOps_post(req, res)).rejects.toThrow();
});
it('saves map ops for a valid job', async () => {
const req = makeReq({
body: {
jobId,
mapOps: { width: 800, height: 600, center: { lat: 0, lng: 0 }, zoom: 10 },
},
});
const res = mockRes();
await jobCtl.saveMapOps_post(req, res);
expect(res.json).toHaveBeenCalled();
});
});
// -------------------------------------------------------------------------
describe('appFiles_post', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns empty array for a job with no app files', async () => {
const req = makeReq({ body: { jobId } });
const res = mockRes();
await jobCtl.appFiles_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
});
it('throws when jobId is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.appFiles_post(req, res)).rejects.toThrow();
});
});
// -------------------------------------------------------------------------
describe('filesdata_post', () => {
it('throws when fileId is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.filesdata_post(req, res)).rejects.toThrow();
});
it('returns paginated result for a valid fileId', async () => {
const req = makeReq({ body: { fileId: String(newId()) } });
const res = mockRes();
await jobCtl.filesdata_post(req, res);
expect(res.json).toHaveBeenCalled();
});
});
// -------------------------------------------------------------------------
describe('getAppDataByJobId', () => {
let jobId;
beforeAll(async () => {
const body = mockJob(applicator._id);
body.client = client._id;
const req = makeReq({ body });
const res = mockRes();
await jobCtl.createJob_post(req, res);
jobId = res._data._id;
});
it('returns null or empty result for a job with no app data', async () => {
const result = await jobCtl.getAppDataByJobId(jobId, '-_id lat lon', { wApps: false, dataOp: 0, wFileId: false, withJob: false });
// No app data seeded result should be null or empty array
expect(result === null || Array.isArray(result)).toBe(true);
});
});
// -------------------------------------------------------------------------
describe('fetchInvReadyJobs_post', () => {
it('returns empty array when no invoice-ready jobs exist', async () => {
const req = makeReq({
body: {},
userInfo: {
puid: String(applicator._id),
kind: '1',
premium: 0,
membership: null,
markedDelete: false,
},
});
const res = mockRes();
await jobCtl.fetchInvReadyJobs_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
});
});
// -------------------------------------------------------------------------
describe('searchJobs_post', () => {
it('throws when byPuid is missing', async () => {
const req = makeReq({ body: {} });
const res = mockRes();
await expect(jobCtl.searchJobs_post(req, res)).rejects.toThrow();
});
it('returns matching jobs for a valid byPuid', async () => {
const req = makeReq({ body: { byPuid: String(applicator._id) } });
const res = mockRes();
await jobCtl.searchJobs_post(req, res);
expect(res.json).toHaveBeenCalled();
expect(Array.isArray(res._data)).toBe(true);
});
});
});