Drop stale label drafts after inactivity and bump version to 0.2.3
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful

This commit is contained in:
2026-04-12 22:29:09 +02:00
parent 39dd474813
commit e50f848896
5 changed files with 221 additions and 11 deletions
+177 -1
View File
@@ -1,8 +1,33 @@
import { describe, expect, it, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const applyItemUpsertMock = vi.fn();
const previewItemUpsertMock = vi.fn();
const printItemLabelMock = vi.fn();
const LABEL_DRAFT_STORAGE_KEY = 'lonc.labels.draft';
let localStorageState;
let localStorageMock;
function createWindowStorageMock(initialState = {}) {
const state = new Map(Object.entries(initialState));
const localStorage = {
getItem: vi.fn((key) => (state.has(key) ? state.get(key) : null)),
setItem: vi.fn((key, value) => {
state.set(key, String(value));
}),
removeItem: vi.fn((key) => {
state.delete(key);
}),
};
vi.stubGlobal('window', { localStorage });
return { state, localStorage };
}
function readStoredLabelDraft() {
const raw = localStorageState.get(LABEL_DRAFT_STORAGE_KEY);
return raw ? JSON.parse(raw) : null;
}
vi.mock('../../../src/api/stock.js', () => ({
applyItemUpsert: (...args) => applyItemUpsertMock(...args),
@@ -23,6 +48,23 @@ vi.mock('../../../src/api/locations.js', () => ({
const { labelCreatePageData } = await import('../../../src/features/labels/label-create-page.js');
describe('label create upsert-first submit', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-04-12T12:00:00Z'));
applyItemUpsertMock.mockReset();
previewItemUpsertMock.mockReset();
printItemLabelMock.mockReset();
const storageMock = createWindowStorageMock();
localStorageState = storageMock.state;
localStorageMock = storageMock.localStorage;
});
afterEach(() => {
vi.useRealTimers();
vi.unstubAllGlobals();
});
it('defaults print checkbox to enabled', () => {
const data = labelCreatePageData({
isConnected: false,
@@ -32,6 +74,132 @@ describe('label create upsert-first submit', () => {
expect(data.printLabelOnSave).toBe(true);
});
it('restores a fresh enveloped draft when inactivity is below 30 minutes', () => {
localStorageState.set(
LABEL_DRAFT_STORAGE_KEY,
JSON.stringify({
form: {
name: 'Draft yogurt',
productionDate: '2026-04-11',
stockType: 'descriptive',
},
savedAt: Date.now() - (29 * 60 * 1000),
}),
);
const data = labelCreatePageData({
isConnected: false,
activeKitchen: { id: 1 },
addAlert: vi.fn(),
});
expect(data.form.name).toBe('Draft yogurt');
expect(data.form.productionDate).toBe('2026-04-11');
expect(data.form.stockType).toBe('descriptive');
});
it('drops stale enveloped drafts at 30 minutes inactivity and loads a clean form', () => {
localStorageState.set(
LABEL_DRAFT_STORAGE_KEY,
JSON.stringify({
form: {
name: 'Old draft',
description: 'Should be removed',
productionDate: '2026-04-10',
stockType: 'measured',
quantity: '4',
uom: 'kg',
},
savedAt: Date.now() - (30 * 60 * 1000),
}),
);
const data = labelCreatePageData({
isConnected: false,
activeKitchen: { id: 1 },
addAlert: vi.fn(),
});
expect(data.form.name).toBe('');
expect(data.form.description).toBe('');
expect(data.form.stockType).toBe('binary');
expect(data.form.quantity).toBe('');
expect(data.form.uom).toBe('g');
expect(data.form.productionDate).toBe('2026-04-12');
});
it('keeps draft when day changes but inactivity stays below 30 minutes', () => {
vi.setSystemTime(new Date('2026-04-12T00:10:00Z'));
localStorageState.set(
LABEL_DRAFT_STORAGE_KEY,
JSON.stringify({
form: {
name: 'Day-changed draft',
productionDate: '2026-04-11',
},
savedAt: Date.now() - (10 * 60 * 1000),
}),
);
const data = labelCreatePageData({
isConnected: false,
activeKitchen: { id: 1 },
addAlert: vi.fn(),
});
expect(data.form.name).toBe('Day-changed draft');
expect(data.form.productionDate).toBe('2026-04-11');
});
it('loads legacy plain-object drafts without forcing discard', () => {
localStorageState.set(
LABEL_DRAFT_STORAGE_KEY,
JSON.stringify({
name: 'Legacy draft',
productionDate: '2026-04-05',
}),
);
const data = labelCreatePageData({
isConnected: false,
activeKitchen: { id: 1 },
addAlert: vi.fn(),
});
expect(data.form.name).toBe('Legacy draft');
expect(data.form.productionDate).toBe('2026-04-05');
});
it('writes enveloped draft payload from persist and reset save paths', () => {
const data = labelCreatePageData({
isConnected: false,
activeKitchen: { id: 1 },
addAlert: vi.fn(),
});
data.form = {
...data.form,
name: 'Persisted entry',
search: 'temp search value',
};
data.persistDraft();
const persistedDraft = readStoredLabelDraft();
expect(persistedDraft.savedAt).toBe(Date.now());
expect(persistedDraft.form.name).toBe('Persisted entry');
expect(persistedDraft.form.search).toBe('');
vi.setSystemTime(new Date('2026-04-12T12:05:00Z'));
data.form.name = 'Reset me';
data.$refs = {};
data.reset(false);
const resetDraft = readStoredLabelDraft();
expect(resetDraft.savedAt).toBe(Date.now());
expect(resetDraft.form.name).toBe('');
expect(resetDraft.form.productionDate).toBe('2026-04-12');
});
it('builds upsert payload with selected template uuid', () => {
const store = {
isConnected: false,
@@ -96,6 +264,13 @@ describe('label create upsert-first submit', () => {
type: 'success',
message: 'Rice was updated successfully.',
});
const savedDraft = readStoredLabelDraft();
expect(savedDraft).toMatchObject({
form: {
name: 'Rice',
},
});
expect(savedDraft.savedAt).toBeTypeOf('number');
});
it('create shows parsed print issue warning when printing fails', async () => {
@@ -129,5 +304,6 @@ describe('label create upsert-first submit', () => {
type: 'warning',
message: 'Beans was created, but printing has an issue: Printer is unavailable.',
});
expect(localStorageMock.setItem).toHaveBeenCalled();
});
});