chore: improve intake reminder observability

This commit is contained in:
Daniel Volz
2026-03-16 21:28:53 +01:00
committed by GitHub
parent 5b019f942d
commit 5138d784cd
8 changed files with 343 additions and 259 deletions
+158 -133
View File
@@ -18,6 +18,14 @@ function createLogger() {
};
}
function mockSelectWhere<T>(result: T) {
return {
from: () => ({
where: async () => result,
}),
} as never;
}
describe("checkAndSendIntakeRemindersForUser", () => {
const mockedDb = vi.mocked(db);
let originalTz: string | undefined;
@@ -45,73 +53,43 @@ describe("checkAndSendIntakeRemindersForUser", () => {
const insertMock = vi.mocked(mockedDb.insert);
selectMock
.mockImplementationOnce(
() =>
({
from: () => ({
where: () => ({
limit: async () => [{ username: "auto-user" }],
}),
}),
}) as never
.mockImplementationOnce(() => mockSelectWhere([{ username: "test-user" }]))
.mockImplementationOnce(() =>
mockSelectWhere([
{
id: 7,
userId: 11,
name: "Vitamin D",
genericName: null,
takenByJson: null,
packageType: "blister",
medicationForm: "tablet",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
looseTablets: 0,
stockAdjustment: 0,
pillWeightMg: null,
doseUnit: "mg",
isObsolete: false,
intakeRemindersEnabled: false,
intakesJson: JSON.stringify([
{
usage: 1,
every: 1,
start: "2026-01-05T08:00:00.000Z",
takenBy: null,
intakeRemindersEnabled: false,
},
]),
usageJson: "[]",
everyJson: "[]",
startJson: "[]",
},
])
)
.mockImplementationOnce(
() =>
({
from: () => ({
where: () => ({
orderBy: async () => [
{
id: 7,
userId: 11,
name: "Vitamin D",
genericName: null,
takenByJson: null,
packageType: "blister",
medicationForm: "tablet",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
looseTablets: 0,
stockAdjustment: 0,
pillWeightMg: null,
doseUnit: "mg",
isObsolete: false,
intakeRemindersEnabled: false,
intakesJson: JSON.stringify([
{
usage: 1,
every: 1,
start: "2026-01-05T08:00:00.000Z",
takenBy: null,
intakeRemindersEnabled: false,
},
]),
usageJson: "[]",
everyJson: "[]",
startJson: "[]",
},
],
}),
}),
}) as never
)
.mockImplementationOnce(
() =>
({
from: () => ({
where: async () => [],
}),
}) as never
)
.mockImplementationOnce(
() =>
({
from: () => ({
where: async () => [],
}),
}) as never
);
.mockImplementationOnce(() => mockSelectWhere([]))
.mockImplementationOnce(() => mockSelectWhere([]));
insertMock.mockImplementation(
() =>
@@ -148,7 +126,7 @@ describe("checkAndSendIntakeRemindersForUser", () => {
takenSource: "automatic",
dismissed: false,
});
expect(logger.info).toHaveBeenCalledWith("[IntakeReminder] Auto-marked 1 due intake dose(s) as taken");
expect(logger.info).toHaveBeenCalledWith("[IntakeReminder] Auto-mark completed for userId=11: inserted=1");
});
it("does not auto-mark due intakes when current stock is empty", async () => {
@@ -157,73 +135,43 @@ describe("checkAndSendIntakeRemindersForUser", () => {
const insertMock = vi.mocked(mockedDb.insert);
selectMock
.mockImplementationOnce(
() =>
({
from: () => ({
where: () => ({
limit: async () => [{ username: "auto-user" }],
}),
}),
}) as never
.mockImplementationOnce(() => mockSelectWhere([{ username: "test-user" }]))
.mockImplementationOnce(() =>
mockSelectWhere([
{
id: 7,
userId: 11,
name: "Vitamin D",
genericName: null,
takenByJson: null,
packageType: "blister",
medicationForm: "tablet",
packCount: 0,
blistersPerPack: 1,
pillsPerBlister: 10,
looseTablets: 0,
stockAdjustment: 0,
pillWeightMg: null,
doseUnit: "mg",
isObsolete: false,
intakeRemindersEnabled: false,
intakesJson: JSON.stringify([
{
usage: 1,
every: 1,
start: "2026-01-05T08:00:00.000Z",
takenBy: null,
intakeRemindersEnabled: false,
},
]),
usageJson: "[]",
everyJson: "[]",
startJson: "[]",
},
])
)
.mockImplementationOnce(
() =>
({
from: () => ({
where: () => ({
orderBy: async () => [
{
id: 7,
userId: 11,
name: "Vitamin D",
genericName: null,
takenByJson: null,
packageType: "blister",
medicationForm: "tablet",
packCount: 0,
blistersPerPack: 1,
pillsPerBlister: 10,
looseTablets: 0,
stockAdjustment: 0,
pillWeightMg: null,
doseUnit: "mg",
isObsolete: false,
intakeRemindersEnabled: false,
intakesJson: JSON.stringify([
{
usage: 1,
every: 1,
start: "2026-01-05T08:00:00.000Z",
takenBy: null,
intakeRemindersEnabled: false,
},
]),
usageJson: "[]",
everyJson: "[]",
startJson: "[]",
},
],
}),
}),
}) as never
)
.mockImplementationOnce(
() =>
({
from: () => ({
where: async () => [],
}),
}) as never
)
.mockImplementationOnce(
() =>
({
from: () => ({
where: async () => [],
}),
}) as never
);
.mockImplementationOnce(() => mockSelectWhere([]))
.mockImplementationOnce(() => mockSelectWhere([]));
insertMock.mockImplementation(
() =>
@@ -255,4 +203,81 @@ describe("checkAndSendIntakeRemindersForUser", () => {
expect(insertedRows).toHaveLength(0);
expect(logger.info).not.toHaveBeenCalledWith("[IntakeReminder] Auto-marked 1 due intake dose(s) as taken");
});
it("suppresses intake notifications entirely when automatic mode and skip-taken reminders are both enabled", async () => {
const insertedRows: Array<Record<string, unknown>> = [];
const selectMock = vi.mocked(mockedDb.select);
const insertMock = vi.mocked(mockedDb.insert);
selectMock
.mockImplementationOnce(() => mockSelectWhere([{ username: "test-user" }]))
.mockImplementationOnce(() =>
mockSelectWhere([
{
id: 7,
userId: 11,
name: "Vitamin D",
genericName: null,
takenByJson: null,
packageType: "blister",
medicationForm: "tablet",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
looseTablets: 0,
stockAdjustment: 0,
pillWeightMg: null,
doseUnit: "mg",
isObsolete: false,
intakeRemindersEnabled: true,
intakesJson: JSON.stringify([
{
usage: 1,
every: 1,
start: "2026-01-05T08:00:00.000Z",
takenBy: null,
intakeRemindersEnabled: true,
},
]),
usageJson: "[]",
everyJson: "[]",
startJson: "[]",
},
])
)
.mockImplementationOnce(() => mockSelectWhere([]))
.mockImplementationOnce(() => mockSelectWhere([]));
insertMock.mockImplementation(
() =>
({
values: async (row: Record<string, unknown>) => {
insertedRows.push(row);
},
}) as never
);
const logger = createLogger();
await checkAndSendIntakeRemindersForUser(
{
userId: 11,
language: "en",
stockCalculationMode: "automatic",
skipRemindersForTakenDoses: true,
emailEnabled: true,
notificationEmail: "user@example.com",
emailIntakeReminders: true,
shoutrrrEnabled: false,
shoutrrrUrl: null,
shoutrrrIntakeReminders: false,
repeatRemindersEnabled: false,
} as never,
logger as never
);
expect(insertedRows).toHaveLength(1);
expect(logger.info).not.toHaveBeenCalledWith("[IntakeReminder] Sending reminder for 1 intakes...");
expect(logger.error).not.toHaveBeenCalled();
});
});