Add label printing functionality and error handling in stock and label flows
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { formatPrintErrorMessage } from '../../src/api/labels.js';
|
||||
|
||||
describe('api/labels formatPrintErrorMessage', () => {
|
||||
it('maps printer_unavailable payload to user-friendly message', () => {
|
||||
const message = formatPrintErrorMessage({
|
||||
status: 503,
|
||||
payload: {
|
||||
code: 'printer_unavailable',
|
||||
message: 'Backend says unavailable',
|
||||
details: { printer: 'Office Zebra' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(message).toBe('Printer is unavailable. (printer: Office Zebra)');
|
||||
});
|
||||
|
||||
it('falls back to generic message when payload is missing', () => {
|
||||
const message = formatPrintErrorMessage(new Error('Something failed'));
|
||||
expect(message).toBe('Something failed');
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const applyItemUpsertMock = vi.fn();
|
||||
const previewItemUpsertMock = vi.fn();
|
||||
const printItemLabelMock = vi.fn();
|
||||
|
||||
vi.mock('../../../src/api/stock.js', () => ({
|
||||
applyItemUpsert: (...args) => applyItemUpsertMock(...args),
|
||||
@@ -11,6 +12,8 @@ vi.mock('../../../src/api/stock.js', () => ({
|
||||
|
||||
vi.mock('../../../src/api/labels.js', () => ({
|
||||
previewLabel: vi.fn(async () => ({ objectUrl: 'blob:preview' })),
|
||||
printItemLabel: (...args) => printItemLabelMock(...args),
|
||||
formatPrintErrorMessage: (error) => error?.message || 'Printing failed.',
|
||||
}));
|
||||
|
||||
vi.mock('../../../src/api/locations.js', () => ({
|
||||
@@ -20,6 +23,15 @@ vi.mock('../../../src/api/locations.js', () => ({
|
||||
const { labelCreatePageData } = await import('../../../src/features/labels/label-create-page.js');
|
||||
|
||||
describe('label create upsert-first submit', () => {
|
||||
it('defaults print checkbox to enabled', () => {
|
||||
const data = labelCreatePageData({
|
||||
isConnected: false,
|
||||
activeKitchen: { id: 1 },
|
||||
addAlert: vi.fn(),
|
||||
});
|
||||
expect(data.printLabelOnSave).toBe(true);
|
||||
});
|
||||
|
||||
it('builds upsert payload with selected template uuid', () => {
|
||||
const store = {
|
||||
isConnected: false,
|
||||
@@ -53,8 +65,9 @@ describe('label create upsert-first submit', () => {
|
||||
it('create uses applyItemUpsert and sets operation-aware success message', async () => {
|
||||
applyItemUpsertMock.mockResolvedValueOnce({
|
||||
operation: 'update',
|
||||
item: { name: 'Rice' },
|
||||
item: { name: 'Rice', uuid_b64: 'uuid-rice-1' },
|
||||
});
|
||||
printItemLabelMock.mockResolvedValueOnce(null);
|
||||
|
||||
const addAlert = vi.fn();
|
||||
const store = {
|
||||
@@ -77,10 +90,44 @@ describe('label create upsert-first submit', () => {
|
||||
|
||||
expect(applyItemUpsertMock).toHaveBeenCalledTimes(1);
|
||||
expect(applyItemUpsertMock.mock.calls[0][1].uuid_b64).toBe('uuid-rice-1');
|
||||
expect(printItemLabelMock).toHaveBeenCalledWith(store, 'uuid-rice-1');
|
||||
expect(data.successMessage).toBe('Rice was updated successfully.');
|
||||
expect(addAlert).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'Rice was updated successfully.',
|
||||
});
|
||||
});
|
||||
|
||||
it('create shows parsed print issue warning when printing fails', async () => {
|
||||
applyItemUpsertMock.mockResolvedValueOnce({
|
||||
operation: 'create',
|
||||
item: { name: 'Beans', uuid_b64: 'uuid-beans-1' },
|
||||
});
|
||||
printItemLabelMock.mockRejectedValueOnce(new Error('Printer is unavailable.'));
|
||||
|
||||
const addAlert = vi.fn();
|
||||
const store = {
|
||||
isConnected: false,
|
||||
activeKitchen: { id: 3 },
|
||||
addAlert,
|
||||
};
|
||||
const data = labelCreatePageData(store);
|
||||
data.validateBeforeSubmit = () => true;
|
||||
data.form = {
|
||||
...data.form,
|
||||
name: 'Beans',
|
||||
stockType: 'binary',
|
||||
locationId: '',
|
||||
productionDate: '2026-04-10',
|
||||
itemUuidB64: '',
|
||||
};
|
||||
|
||||
await data.create();
|
||||
|
||||
expect(data.printIssue).toBe('Printer is unavailable.');
|
||||
expect(addAlert).toHaveBeenCalledWith({
|
||||
type: 'warning',
|
||||
message: 'Beans was created, but printing has an issue: Printer is unavailable.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const printItemLabelMock = vi.fn();
|
||||
const formatPrintErrorMessageMock = vi.fn();
|
||||
|
||||
vi.mock('../../../src/api/labels.js', () => ({
|
||||
printItemLabel: (...args) => printItemLabelMock(...args),
|
||||
formatPrintErrorMessage: (...args) => formatPrintErrorMessageMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock('../../../src/api/stock.js', () => ({
|
||||
getStockEntry: vi.fn(),
|
||||
adjustStockEntry: vi.fn(),
|
||||
useStockItem: vi.fn(),
|
||||
listStockEntries: vi.fn(async () => []),
|
||||
listGroupedStockEntries: vi.fn(async () => []),
|
||||
updateStockItem: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../src/api/locations.js', () => ({
|
||||
fetchLocations: vi.fn(async () => ({ flat: [], tree: [] })),
|
||||
}));
|
||||
|
||||
const { stockDetailPageData } = await import('../../../src/features/stock/stock-detail-page.js');
|
||||
|
||||
describe('stock print label actions', () => {
|
||||
beforeEach(() => {
|
||||
printItemLabelMock.mockReset();
|
||||
formatPrintErrorMessageMock.mockReset();
|
||||
globalThis.window = {
|
||||
__loncApp: {
|
||||
navigate: vi.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
delete globalThis.window;
|
||||
});
|
||||
|
||||
it('prints from stock detail and shows success alert', async () => {
|
||||
printItemLabelMock.mockResolvedValueOnce(null);
|
||||
const addAlert = vi.fn();
|
||||
const store = { addAlert };
|
||||
const data = stockDetailPageData(store);
|
||||
data.entry = { uuid_b64: 'uuid-1', name: 'Rice' };
|
||||
|
||||
await data.printLabel();
|
||||
|
||||
expect(printItemLabelMock).toHaveBeenCalledWith(store, 'uuid-1');
|
||||
expect(addAlert).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'Rice label sent to printer.',
|
||||
});
|
||||
});
|
||||
|
||||
it('shows parsed warning when detail printing fails', async () => {
|
||||
printItemLabelMock.mockRejectedValueOnce(new Error('boom'));
|
||||
formatPrintErrorMessageMock.mockReturnValueOnce('Printer unavailable.');
|
||||
const addAlert = vi.fn();
|
||||
const store = { addAlert };
|
||||
const data = stockDetailPageData(store);
|
||||
data.entry = { uuid_b64: 'uuid-1', name: 'Rice' };
|
||||
|
||||
await data.printLabel();
|
||||
|
||||
expect(addAlert).toHaveBeenCalledWith({
|
||||
type: 'warning',
|
||||
message: 'Could not print Rice label: Printer unavailable.',
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user