Quality gates / quality (pull_request) Successful in 3m9s
A confirmed log and the image attached to it are separate things the person owns. The journal now reports a saved photo as a label instead of a thumbnail, reveals the image only on explicit request, removes the photo without touching any confirmed field, and deletes a log through a separate two-step decision that takes its photo with it. Delete-all is regression tested to remove the ledger and every stored photo together. - src/photo-lifecycle.js: presence decided by stored image bytes; withoutPhoto/withoutEntry return new lists and never mutate the ledger - app.js: journal rows expose Open-entry controls; entry sheet states presence, offers explicit reveal, remove-photo-keeps-log, and a two-step log delete; privacy copy names photo removal and delete-all - tests: 6 unit cases + browser acceptance (presence, no default thumbnail, explicit reveal, remove keeps log, two-step delete, delete-all leaves no image bytes, Escape dismiss, 44px targets) - record_release_demo.mjs: on-camera photo lifecycle scenes driven by a synthetic 1x1 PNG, with delete-all actually performed and asserted; build_release gates the new captions - CI/release/syntax gates include the new suite Closes #36
72 lines
2.6 KiB
JavaScript
72 lines
2.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { photoCount, photoState, withoutEntry, withoutPhoto } from '../src/photo-lifecycle.js';
|
|
|
|
const entry = (id, photoDataUrl = '', overrides = {}) => ({
|
|
id,
|
|
occurredAt: '2026-10-14T07:20:00.000Z',
|
|
bristolType: 4,
|
|
color: 'brown',
|
|
urgency: 1,
|
|
discomfort: 0,
|
|
note: '',
|
|
photoDataUrl,
|
|
symptoms: { blood: false },
|
|
...overrides,
|
|
});
|
|
|
|
test('photo state is decided by the saved image bytes, not a filename or a flag', () => {
|
|
assert.deepEqual(photoState(entry('a', 'data:image/png;base64,AAAA')), {
|
|
hasPhoto: true,
|
|
label: 'Photo saved',
|
|
});
|
|
});
|
|
|
|
test('a log with no usable image reports that no photo is saved', () => {
|
|
for (const value of [undefined, '', 'synthetic-type4.jpg', 'data:text/plain;base64,AAAA', 42]) {
|
|
assert.deepEqual(photoState(entry('a', value)), { hasPhoto: false, label: '' });
|
|
}
|
|
});
|
|
|
|
test('removing a photo clears only the image bytes and keeps the confirmed log intact', () => {
|
|
const before = entry('a', 'data:image/png;base64,AAAA', { note: 'after lunch', bristolType: 3 });
|
|
const [after] = withoutPhoto([before], 'a');
|
|
|
|
assert.equal(after.id, before.id);
|
|
assert.equal(after.occurredAt, before.occurredAt);
|
|
assert.equal(after.bristolType, 3);
|
|
assert.equal(after.note, 'after lunch');
|
|
assert.deepEqual(after.symptoms, before.symptoms);
|
|
assert.equal(after.photoDataUrl, '');
|
|
});
|
|
|
|
test('removing a photo never mutates the ledger it was given and leaves other logs alone', () => {
|
|
const withPhoto = entry('a', 'data:image/png;base64,AAAA');
|
|
const withoutOne = entry('b', '', { note: 'no photo here' });
|
|
const input = [withPhoto, withoutOne];
|
|
|
|
const result = withoutPhoto(input, 'a');
|
|
|
|
assert.notEqual(result, input);
|
|
assert.equal(input[0].photoDataUrl, 'data:image/png;base64,AAAA');
|
|
assert.deepEqual(result[1], withoutOne);
|
|
assert.deepEqual(withoutPhoto(input, 'missing'), input);
|
|
assert.equal(withoutPhoto(input, 'missing')[0], input[0]);
|
|
});
|
|
|
|
test('deleting a log removes exactly that confirmed entry, photo included', () => {
|
|
const input = [entry('a', 'data:image/png;base64,AAAA'), entry('b'), entry('c', '', { bristolType: 6 })];
|
|
|
|
const result = withoutEntry(input, 'a');
|
|
|
|
assert.deepEqual(result.map(item => item.id), ['b', 'c']);
|
|
assert.equal(input.length, 3);
|
|
assert.deepEqual(withoutEntry(input, 'missing'), input);
|
|
});
|
|
|
|
test('photo count reports how many confirmed logs still hold an image', () => {
|
|
assert.equal(photoCount([entry('a', 'data:image/png;base64,AAAA'), entry('b'), entry('c', 'data:image/jpeg;base64,BBBB')]), 2);
|
|
assert.equal(photoCount([]), 0);
|
|
assert.equal(photoCount(undefined), 0);
|
|
});
|