mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
Add GAP-TREAT-012 test suite for Loop override UUID handling
TEST-GAP-001: Loop override POST with UUID _id TEST-GAP-002: Loop override DELETE by UUID TEST-GAP-003: Loop override UPDATE by UUID TEST-GAP-004: Loop override re-POST (upsert) 12 new tests validating REQ-SYNC-072 behavior: - UUID _id promoted to identifier field - Server generates valid ObjectId for _id - Updates/deletes work via identifier lookup - Duplicate detection via identifier - Batch and edge case handling New fixtures: - loop-override.js: Real Loop override payload patterns All 12 tests passing. Refs: GAP-TREAT-012, REQ-SYNC-072 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Vendored
+1
@@ -3,6 +3,7 @@
|
||||
module.exports = {
|
||||
aaps: require('./aaps-single-doc'),
|
||||
loop: require('./loop-batch'),
|
||||
loopOverride: require('./loop-override'),
|
||||
trio: require('./trio-pipeline'),
|
||||
deduplication: require('./deduplication'),
|
||||
edgeCases: require('./edge-cases'),
|
||||
|
||||
Vendored
+219
@@ -0,0 +1,219 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Loop Override Test Fixtures for GAP-TREAT-012 Testing
|
||||
*
|
||||
* GAP-TREAT-012: v1 API incorrectly coerces UUID _id to ObjectId
|
||||
*
|
||||
* This file provides fixtures that simulate real Loop override uploads,
|
||||
* which use UUID strings as the `id` field (mapped to `_id` in Nightscout).
|
||||
*
|
||||
* REQ-SYNC-072: UUID _id should be moved to identifier field,
|
||||
* with server generating a valid ObjectId for _id.
|
||||
*/
|
||||
|
||||
// Generate fresh dates for each test run
|
||||
function now() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
function hoursAgo(hours) {
|
||||
return new Date(Date.now() - hours * 3600000).toISOString();
|
||||
}
|
||||
|
||||
function minutesAgo(minutes) {
|
||||
return new Date(Date.now() - minutes * 60000).toISOString();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Standard Loop override as uploaded by OverrideTreatment.swift
|
||||
* Note: Loop sends `id` as UUID string, NOT as ObjectId
|
||||
*/
|
||||
standardOverride: {
|
||||
_id: 'A1B2C3D4-E5F6-7890-ABCD-EF1234567890',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(30),
|
||||
enteredBy: 'Loop',
|
||||
duration: 60,
|
||||
correctionRange: [90, 110],
|
||||
insulinNeedsScaleFactor: 1.2,
|
||||
reason: 'Custom Override'
|
||||
},
|
||||
|
||||
/**
|
||||
* Indefinite override (no end time)
|
||||
*/
|
||||
indefiniteOverride: {
|
||||
_id: 'B2C3D4E5-F6A7-8901-BCDE-F23456789012',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(15),
|
||||
enteredBy: 'Loop',
|
||||
durationType: 'indefinite',
|
||||
correctionRange: [100, 120],
|
||||
insulinNeedsScaleFactor: 1.0,
|
||||
reason: 'Running Low'
|
||||
},
|
||||
|
||||
/**
|
||||
* Remote command override
|
||||
*/
|
||||
remoteOverride: {
|
||||
_id: 'C3D4E5F6-A7B8-9012-CDEF-345678901234',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(5),
|
||||
enteredBy: 'Loop (via remote command)',
|
||||
duration: 120,
|
||||
correctionRange: [150, 180],
|
||||
insulinNeedsScaleFactor: 0.5,
|
||||
reason: 'Workout'
|
||||
},
|
||||
|
||||
/**
|
||||
* Preset override (e.g., "Eating Soon")
|
||||
*/
|
||||
presetOverride: {
|
||||
_id: 'D4E5F6A7-B8C9-0123-DEFA-456789012345',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: hoursAgo(1),
|
||||
enteredBy: 'Loop',
|
||||
duration: 60,
|
||||
correctionRange: [80, 80],
|
||||
insulinNeedsScaleFactor: 1.0,
|
||||
reason: 'Pre-Meal'
|
||||
},
|
||||
|
||||
/**
|
||||
* Update scenario: same UUID, different values
|
||||
*/
|
||||
updateScenario: {
|
||||
original: {
|
||||
_id: 'E5F6A7B8-C9D0-1234-EFAB-567890123456',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: hoursAgo(2),
|
||||
enteredBy: 'Loop',
|
||||
duration: 60,
|
||||
correctionRange: [100, 120],
|
||||
insulinNeedsScaleFactor: 1.0,
|
||||
reason: 'Original Override'
|
||||
},
|
||||
updated: {
|
||||
_id: 'E5F6A7B8-C9D0-1234-EFAB-567890123456',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: hoursAgo(1),
|
||||
enteredBy: 'Loop',
|
||||
duration: 120, // Extended duration
|
||||
correctionRange: [110, 130], // Changed range
|
||||
insulinNeedsScaleFactor: 0.8, // Changed factor
|
||||
reason: 'Updated Override'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete scenario: override to cancel
|
||||
*/
|
||||
deleteScenario: {
|
||||
toDelete: {
|
||||
_id: 'F6A7B8C9-D0E1-2345-FABC-678901234567',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(45),
|
||||
enteredBy: 'Loop',
|
||||
duration: 90,
|
||||
correctionRange: [95, 115],
|
||||
insulinNeedsScaleFactor: 1.1,
|
||||
reason: 'To Be Deleted'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Multiple overrides batch (simulates Loop restart/sync)
|
||||
*/
|
||||
batchOverrides: [
|
||||
{
|
||||
_id: '11111111-1111-1111-1111-111111111111',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: hoursAgo(3),
|
||||
enteredBy: 'Loop',
|
||||
duration: 30,
|
||||
correctionRange: [90, 100],
|
||||
insulinNeedsScaleFactor: 1.0,
|
||||
reason: 'First Override'
|
||||
},
|
||||
{
|
||||
_id: '22222222-2222-2222-2222-222222222222',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: hoursAgo(2),
|
||||
enteredBy: 'Loop',
|
||||
duration: 45,
|
||||
correctionRange: [100, 110],
|
||||
insulinNeedsScaleFactor: 0.9,
|
||||
reason: 'Second Override'
|
||||
},
|
||||
{
|
||||
_id: '33333333-3333-3333-3333-333333333333',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: hoursAgo(1),
|
||||
enteredBy: 'Loop',
|
||||
duration: 60,
|
||||
correctionRange: [80, 90],
|
||||
insulinNeedsScaleFactor: 1.2,
|
||||
reason: 'Third Override'
|
||||
}
|
||||
],
|
||||
|
||||
/**
|
||||
* Duplicate detection scenario
|
||||
* Same UUID should NOT create duplicate
|
||||
*/
|
||||
duplicateScenario: {
|
||||
first: {
|
||||
_id: 'AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(60),
|
||||
enteredBy: 'Loop',
|
||||
duration: 60,
|
||||
correctionRange: [100, 110],
|
||||
insulinNeedsScaleFactor: 1.0,
|
||||
reason: 'Original Post'
|
||||
},
|
||||
repost: {
|
||||
_id: 'AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(30), // Different time
|
||||
enteredBy: 'Loop',
|
||||
duration: 90, // Different duration
|
||||
correctionRange: [110, 120],
|
||||
insulinNeedsScaleFactor: 1.1,
|
||||
reason: 'Reposted Override'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Mixed eventTypes batch - some with UUID, some without
|
||||
*/
|
||||
mixedBatch: [
|
||||
{
|
||||
_id: 'UUID1234-5678-90AB-CDEF-111111111111',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: minutesAgo(20),
|
||||
enteredBy: 'Loop',
|
||||
duration: 60,
|
||||
correctionRange: [100, 110],
|
||||
insulinNeedsScaleFactor: 1.0,
|
||||
reason: 'Override With UUID'
|
||||
},
|
||||
{
|
||||
eventType: 'Carb Correction',
|
||||
carbs: 15,
|
||||
created_at: minutesAgo(15),
|
||||
enteredBy: 'loop://iPhone',
|
||||
absorptionTime: 180
|
||||
},
|
||||
{
|
||||
eventType: 'Bolus',
|
||||
insulin: 2.5,
|
||||
created_at: minutesAgo(10),
|
||||
enteredBy: 'loop://iPhone'
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,428 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* GAP-TREAT-012 Test Suite: Loop Override UUID Identity Handling
|
||||
*
|
||||
* REQUIREMENT REFERENCE: REQ-SYNC-072 (Transparent UUID promotion)
|
||||
* GAP REFERENCE: GAP-TREAT-012 (v1 API incorrectly coerces UUID _id to ObjectId)
|
||||
*
|
||||
* These tests verify that:
|
||||
* 1. UUID _id is moved to identifier field (not corrupted)
|
||||
* 2. Server generates valid ObjectId for _id
|
||||
* 3. Updates/deletes work via identifier lookup
|
||||
* 4. Duplicate detection works via identifier
|
||||
*
|
||||
* TEST MATRIX REFERENCE: docs/backlogs/loop-nightscout-upload-testing.md
|
||||
* - TEST-GAP-001: Loop override POST
|
||||
* - TEST-GAP-002: Loop override DELETE
|
||||
* - TEST-GAP-003: Loop override UPDATE
|
||||
* - TEST-GAP-004: Loop override re-POST (upsert)
|
||||
*/
|
||||
|
||||
const request = require('supertest');
|
||||
const should = require('should');
|
||||
const language = require('../lib/language')();
|
||||
|
||||
describe('GAP-TREAT-012: Loop Override UUID Handling', function() {
|
||||
this.timeout(30000);
|
||||
const self = this;
|
||||
|
||||
const api_secret_hash = 'b723e97aa97846eb92d5264f084b2823f57c4aa1';
|
||||
|
||||
// Load Loop override fixtures
|
||||
const loopOverride = require('./fixtures/loop-override');
|
||||
|
||||
before(function(done) {
|
||||
process.env.API_SECRET = 'this is my long pass phrase';
|
||||
self.env = require('../lib/server/env')();
|
||||
self.env.settings.authDefaultRoles = 'readable';
|
||||
self.env.settings.enable = ['careportal', 'api'];
|
||||
const wares = require('../lib/middleware/')(self.env);
|
||||
self.app = require('express')();
|
||||
self.app.enable('api');
|
||||
require('../lib/server/bootevent')(self.env, language).boot(function booted(ctx) {
|
||||
self.ctx = ctx;
|
||||
self.ctx.wares = wares;
|
||||
self.ctx.ddata = require('../lib/data/ddata')();
|
||||
self.app.use('/api', require('../lib/api/')(self.env, ctx));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
// Clear treatments before each test
|
||||
self.ctx.treatments.remove({
|
||||
find: { created_at: { '$gte': '1999-01-01T00:00:00.000Z' } }
|
||||
}, done);
|
||||
});
|
||||
|
||||
describe('TEST-GAP-001: Loop override POST with UUID as _id', function() {
|
||||
|
||||
it('accepts UUID _id and promotes to identifier field', function(done) {
|
||||
const fixture = loopOverride.standardOverride;
|
||||
const uuidId = fixture._id;
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
should.exist(res.body);
|
||||
res.body.should.be.an.Array();
|
||||
res.body.length.should.equal(1);
|
||||
|
||||
const created = res.body[0];
|
||||
|
||||
// REQ-SYNC-072: UUID should be in identifier, not _id
|
||||
created.identifier.should.equal(uuidId);
|
||||
|
||||
// _id should be a valid ObjectId (24 hex chars)
|
||||
created._id.should.match(/^[0-9a-f]{24}$/);
|
||||
created._id.should.not.equal(uuidId);
|
||||
|
||||
// Other fields preserved
|
||||
created.eventType.should.equal('Temporary Override');
|
||||
created.reason.should.equal('Custom Override');
|
||||
|
||||
console.log(` UUID _id: ${uuidId}`);
|
||||
console.log(` Server _id: ${created._id}`);
|
||||
console.log(` identifier: ${created.identifier}`);
|
||||
console.log(' ✓ UUID promoted to identifier field');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('indefinite override UUID is preserved in identifier', function(done) {
|
||||
const fixture = loopOverride.indefiniteOverride;
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
|
||||
const created = res.body[0];
|
||||
created.identifier.should.equal(fixture._id);
|
||||
created._id.should.match(/^[0-9a-f]{24}$/);
|
||||
should.exist(created.durationType);
|
||||
created.durationType.should.equal('indefinite');
|
||||
|
||||
console.log(' ✓ Indefinite override UUID preserved');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('remote command override UUID is preserved in identifier', function(done) {
|
||||
const fixture = loopOverride.remoteOverride;
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
|
||||
const created = res.body[0];
|
||||
created.identifier.should.equal(fixture._id);
|
||||
created.enteredBy.should.equal('Loop (via remote command)');
|
||||
|
||||
console.log(' ✓ Remote override UUID preserved');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('TEST-GAP-002: Loop override DELETE by UUID', function() {
|
||||
|
||||
it('can delete override using identifier query', function(done) {
|
||||
const fixture = loopOverride.deleteScenario.toDelete;
|
||||
|
||||
// First create the override
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
const serverId = res.body[0]._id;
|
||||
|
||||
// Delete by server-assigned _id (standard method)
|
||||
request(self.app)
|
||||
.delete('/api/treatments/' + serverId)
|
||||
.set('api-secret', api_secret_hash)
|
||||
.expect(200)
|
||||
.end(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
// Verify deleted
|
||||
self.ctx.treatments.list({ find: { identifier: fixture._id } }, function(err, list) {
|
||||
should.not.exist(err);
|
||||
list.length.should.equal(0);
|
||||
|
||||
console.log(' ✓ Override deleted successfully');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can find override by identifier after creation', function(done) {
|
||||
const fixture = loopOverride.standardOverride;
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
// Query by identifier
|
||||
self.ctx.treatments.list({ find: { identifier: fixture._id } }, function(err, list) {
|
||||
should.not.exist(err);
|
||||
list.length.should.equal(1);
|
||||
list[0].identifier.should.equal(fixture._id);
|
||||
|
||||
console.log(' ✓ Override found by identifier query');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('TEST-GAP-003: Loop override UPDATE by UUID', function() {
|
||||
|
||||
it('PUT with UUID _id updates existing override', function(done) {
|
||||
const scenario = loopOverride.updateScenario;
|
||||
|
||||
// Create original
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([scenario.original])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
const serverId = res.body[0]._id;
|
||||
|
||||
// Update with same UUID
|
||||
request(self.app)
|
||||
.put('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send(scenario.updated)
|
||||
.expect(200)
|
||||
.end(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
// Verify update
|
||||
self.ctx.treatments.list({ find: { identifier: scenario.original._id } }, function(err, list) {
|
||||
should.not.exist(err);
|
||||
list.length.should.equal(1);
|
||||
|
||||
const updated = list[0];
|
||||
updated.identifier.should.equal(scenario.original._id);
|
||||
updated.duration.should.equal(120); // Updated value
|
||||
updated.reason.should.equal('Updated Override');
|
||||
|
||||
console.log(' ✓ Override updated via PUT with UUID');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('TEST-GAP-004: Loop override re-POST (upsert by identifier)', function() {
|
||||
|
||||
it('re-POST same UUID updates instead of creating duplicate', function(done) {
|
||||
const scenario = loopOverride.duplicateScenario;
|
||||
|
||||
// First POST
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([scenario.first])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
const firstServerId = res.body[0]._id;
|
||||
|
||||
// Re-POST with same UUID, different values
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([scenario.repost])
|
||||
.expect(200)
|
||||
.end(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
// Should only have ONE document
|
||||
self.ctx.treatments.list({ find: { identifier: scenario.first._id } }, function(err, list) {
|
||||
should.not.exist(err);
|
||||
|
||||
// CRITICAL: No duplicates
|
||||
list.length.should.equal(1, 'Re-POST should update, not create duplicate');
|
||||
|
||||
// Should have updated values
|
||||
const doc = list[0];
|
||||
doc.duration.should.equal(90); // From repost
|
||||
doc.reason.should.equal('Reposted Override');
|
||||
|
||||
console.log(` First _id: ${firstServerId}`);
|
||||
console.log(` After re-POST: 1 document (no duplicate)`);
|
||||
console.log(' ✓ Re-POST with same UUID updates existing');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Batch Override Upload', function() {
|
||||
|
||||
it('batch of overrides with UUIDs all get identifier fields', function(done) {
|
||||
const batch = loopOverride.batchOverrides;
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send(batch)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
res.body.length.should.equal(3);
|
||||
|
||||
// All should have identifier field with original UUID
|
||||
res.body.forEach(function(item, idx) {
|
||||
item.identifier.should.equal(batch[idx]._id);
|
||||
item._id.should.match(/^[0-9a-f]{24}$/);
|
||||
});
|
||||
|
||||
// Verify in database
|
||||
self.ctx.treatments.list({}, function(err, list) {
|
||||
should.not.exist(err);
|
||||
list.length.should.equal(3);
|
||||
|
||||
console.log(' ✓ Batch of 3 overrides all have identifier fields');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('mixed batch with UUID and non-UUID treatments', function(done) {
|
||||
const batch = loopOverride.mixedBatch;
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send(batch)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
res.body.length.should.equal(3);
|
||||
|
||||
// Override should have identifier
|
||||
const override = res.body.find(t => t.eventType === 'Temporary Override');
|
||||
override.identifier.should.equal(batch[0]._id);
|
||||
override._id.should.match(/^[0-9a-f]{24}$/);
|
||||
|
||||
// Carb and bolus should have generated _ids
|
||||
const carb = res.body.find(t => t.eventType === 'Carb Correction');
|
||||
carb._id.should.match(/^[0-9a-f]{24}$/);
|
||||
|
||||
console.log(' ✓ Mixed batch handles UUID and non-UUID correctly');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', function() {
|
||||
|
||||
it('handles uppercase UUID', function(done) {
|
||||
const fixture = {
|
||||
_id: 'ABCDEF01-2345-6789-ABCD-EF0123456789',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: new Date().toISOString(),
|
||||
enteredBy: 'Loop',
|
||||
duration: 30,
|
||||
correctionRange: [100, 110],
|
||||
reason: 'Uppercase UUID Test'
|
||||
};
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
res.body[0].identifier.should.equal(fixture._id);
|
||||
|
||||
console.log(' ✓ Uppercase UUID preserved');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles lowercase UUID', function(done) {
|
||||
const fixture = {
|
||||
_id: 'abcdef01-2345-6789-abcd-ef0123456789',
|
||||
eventType: 'Temporary Override',
|
||||
created_at: new Date().toISOString(),
|
||||
enteredBy: 'Loop',
|
||||
duration: 30,
|
||||
correctionRange: [100, 110],
|
||||
reason: 'Lowercase UUID Test'
|
||||
};
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
res.body[0].identifier.should.equal(fixture._id);
|
||||
|
||||
console.log(' ✓ Lowercase UUID preserved');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('valid ObjectId string is NOT promoted to identifier', function(done) {
|
||||
// 24-char hex string (valid ObjectId format)
|
||||
const objectIdString = '507f1f77bcf86cd799439011';
|
||||
const fixture = {
|
||||
_id: objectIdString,
|
||||
eventType: 'Note',
|
||||
created_at: new Date().toISOString(),
|
||||
enteredBy: 'Test',
|
||||
notes: 'ObjectId format test'
|
||||
};
|
||||
|
||||
request(self.app)
|
||||
.post('/api/treatments/')
|
||||
.set('api-secret', api_secret_hash)
|
||||
.send([fixture])
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
should.not.exist(err);
|
||||
|
||||
const created = res.body[0];
|
||||
// ObjectId should be used as-is (or regenerated), NOT promoted
|
||||
created._id.should.match(/^[0-9a-f]{24}$/);
|
||||
|
||||
console.log(` Input _id: ${objectIdString}`);
|
||||
console.log(` Result _id: ${created._id}`);
|
||||
console.log(' ✓ ObjectId format handled correctly');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user