Skip to content

Commit b2ddc3c

Browse files
test(barcode-generator-web): cover Data Matrix generation
Adds config-mapping and validation unit tests plus render tests asserting encoder selection (plain vs GS1, rectangular) and the malformed-GS1 error path. Mocks bwip-js and adds the new required Data Matrix props to the shared test props builder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f6285d5 commit b2ddc3c

3 files changed

Lines changed: 192 additions & 0 deletions

File tree

packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import "@testing-library/jest-dom";
2+
import * as bwip from "@bwip-js/browser";
23
import { fireEvent, render, screen } from "@testing-library/react";
34
import userEvent from "@testing-library/user-event";
45
import { Big } from "big.js";
@@ -33,6 +34,19 @@ jest.mock("../utils/download-code", () => ({
3334
downloadCode: jest.fn()
3435
}));
3536

37+
// Mock bwip-js (ESM-only, not resolvable in jest without transform)
38+
jest.mock(
39+
"@bwip-js/browser",
40+
() => ({
41+
drawingSVG: jest.fn(() => ({})),
42+
datamatrix: jest.fn(() => "<svg data-testid='datamatrix'></svg>"),
43+
datamatrixrectangular: jest.fn(() => "<svg data-testid='datamatrix-rect'></svg>"),
44+
gs1datamatrix: jest.fn(() => "<svg data-testid='gs1datamatrix'></svg>"),
45+
gs1datamatrixrectangular: jest.fn(() => "<svg data-testid='gs1datamatrix-rect'></svg>")
46+
}),
47+
{ virtual: true }
48+
);
49+
3650
import {
3751
BarcodeGeneratorContainerProps,
3852
CodeFormatEnum,
@@ -69,6 +83,9 @@ const createBarcodeProps = (
6983
codeMargin: 4,
7084
qrSize: 128,
7185
qrMargin: 2,
86+
dmGs1Mode: false,
87+
dmShape: "square",
88+
dmSize: 128,
7289
qrTitle: dynamic.available(""),
7390
qrLevel: "L",
7491
qrOverlay: false,
@@ -1036,4 +1053,67 @@ describe("BarcodeGenerator", () => {
10361053
expect(screen.getByText("Export")).toBeInTheDocument();
10371054
});
10381055
});
1056+
1057+
describe("Data Matrix", () => {
1058+
beforeEach(() => {
1059+
jest.clearAllMocks();
1060+
});
1061+
1062+
it("renders a plain Data Matrix using the datamatrix encoder", () => {
1063+
const props = createBarcodeProps({
1064+
codeFormat: "DataMatrix" as CodeFormatEnum,
1065+
codeValue: dynamic.available("ABC-12345")
1066+
});
1067+
1068+
render(<BarcodeGenerator {...props} />);
1069+
1070+
expect(bwip.datamatrix).toHaveBeenCalledWith(
1071+
expect.objectContaining({ bcid: "datamatrix", text: "ABC-12345" }),
1072+
expect.anything()
1073+
);
1074+
expect(bwip.gs1datamatrix).not.toHaveBeenCalled();
1075+
});
1076+
1077+
it("uses the gs1datamatrix encoder in GS1 mode", () => {
1078+
const props = createBarcodeProps({
1079+
codeFormat: "DataMatrix" as CodeFormatEnum,
1080+
dmGs1Mode: true,
1081+
codeValue: dynamic.available("(01)09501101020917(17)261231(10)ABC123")
1082+
});
1083+
1084+
render(<BarcodeGenerator {...props} />);
1085+
1086+
expect(bwip.gs1datamatrix).toHaveBeenCalledWith(
1087+
expect.objectContaining({ bcid: "gs1datamatrix", parse: true }),
1088+
expect.anything()
1089+
);
1090+
expect(bwip.datamatrix).not.toHaveBeenCalled();
1091+
});
1092+
1093+
it("uses the rectangular encoder for the rectangle shape", () => {
1094+
const props = createBarcodeProps({
1095+
codeFormat: "DataMatrix" as CodeFormatEnum,
1096+
dmShape: "rectangle",
1097+
codeValue: dynamic.available("RECT")
1098+
});
1099+
1100+
render(<BarcodeGenerator {...props} />);
1101+
1102+
expect(bwip.datamatrixrectangular).toHaveBeenCalled();
1103+
});
1104+
1105+
it("shows the error alert when GS1 syntax is malformed and log level is not None", () => {
1106+
const props = createBarcodeProps({
1107+
codeFormat: "DataMatrix" as CodeFormatEnum,
1108+
dmGs1Mode: true,
1109+
logLevel: "Debug",
1110+
codeValue: dynamic.available("not-a-valid-ai")
1111+
});
1112+
1113+
render(<BarcodeGenerator {...props} />);
1114+
1115+
expect(screen.getByText(/Unable to generate Data Matrix/)).toBeInTheDocument();
1116+
expect(bwip.gs1datamatrix).not.toHaveBeenCalled();
1117+
});
1118+
});
10391119
});
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { Big } from "big.js";
2+
import { dynamic } from "@mendix/widget-plugin-test-utils";
3+
import { BarcodeGeneratorContainerProps } from "../../../typings/BarcodeGeneratorProps";
4+
import { barcodeConfig, DataMatrixTypeConfig } from "../Barcode.config";
5+
6+
function props(overrides: Partial<BarcodeGeneratorContainerProps> = {}): BarcodeGeneratorContainerProps {
7+
return {
8+
name: "bg1",
9+
class: "",
10+
tabIndex: -1,
11+
codeValue: dynamic.available("ABC123"),
12+
codeFormat: "DataMatrix",
13+
customCodeFormat: "CODE128",
14+
enableEan128: false,
15+
enableFlat: false,
16+
lastChar: "",
17+
enableMod43: false,
18+
allowDownload: false,
19+
buttonPosition: "bottom",
20+
addonFormat: "None",
21+
addonValue: dynamic.available(""),
22+
addonSpacing: 20,
23+
displayValue: false,
24+
showAsCard: false,
25+
codeWidth: 2,
26+
codeHeight: 200,
27+
codeMargin: 4,
28+
qrSize: 128,
29+
qrMargin: 2,
30+
dmGs1Mode: false,
31+
dmShape: "square",
32+
dmSize: 128,
33+
qrTitle: dynamic.available("QR"),
34+
qrLevel: "L",
35+
qrOverlay: false,
36+
qrOverlaySrc: dynamic.available({ uri: "" } as any),
37+
qrOverlayCenter: true,
38+
qrOverlayX: 0,
39+
qrOverlayY: 0,
40+
qrOverlayHeight: 24,
41+
qrOverlayWidth: 24,
42+
qrOverlayOpacity: new Big(1),
43+
qrOverlayExcavate: true,
44+
logLevel: "None",
45+
...overrides
46+
} as BarcodeGeneratorContainerProps;
47+
}
48+
49+
describe("barcodeConfig - DataMatrix", () => {
50+
it("maps DataMatrix format to a datamatrix config", () => {
51+
const config = barcodeConfig(props()) as DataMatrixTypeConfig;
52+
expect(config.type).toBe("datamatrix");
53+
expect(config.codeValue).toBe("ABC123");
54+
expect(config.size).toBe(128);
55+
expect(config.shape).toBe("square");
56+
expect(config.gs1Mode).toBe(false);
57+
});
58+
59+
it("carries GS1 mode and rectangular shape", () => {
60+
const config = barcodeConfig(props({ dmGs1Mode: true, dmShape: "rectangle" })) as DataMatrixTypeConfig;
61+
expect(config.gs1Mode).toBe(true);
62+
expect(config.shape).toBe("rectangle");
63+
});
64+
65+
it("uses the DataMatrix margin from codeMargin", () => {
66+
const config = barcodeConfig(props({ codeMargin: 6 })) as DataMatrixTypeConfig;
67+
expect(config.margin).toBe(6);
68+
});
69+
70+
it("does not route non-DataMatrix formats to datamatrix", () => {
71+
expect(barcodeConfig(props({ codeFormat: "QRCode" })).type).toBe("qrcode");
72+
expect(barcodeConfig(props({ codeFormat: "CODE128" })).type).toBe("barcode");
73+
});
74+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { validateBarcodeValue, validateGs1DataMatrixValue } from "../validation";
2+
3+
describe("validateBarcodeValue - DataMatrix", () => {
4+
it("passes for an empty value (dynamic binding at runtime)", () => {
5+
expect(validateBarcodeValue("DataMatrix", "")).toEqual({ valid: true });
6+
});
7+
8+
it("passes for a plain string", () => {
9+
expect(validateBarcodeValue("DataMatrix", "ABC-12345")).toEqual({ valid: true });
10+
});
11+
12+
it("rejects an excessively long value", () => {
13+
const result = validateBarcodeValue("DataMatrix", "x".repeat(2001));
14+
expect(result.valid).toBe(false);
15+
});
16+
});
17+
18+
describe("validateGs1DataMatrixValue", () => {
19+
it("passes for an empty value", () => {
20+
expect(validateGs1DataMatrixValue("")).toEqual({ valid: true });
21+
});
22+
23+
it("passes for valid GS1 AI syntax", () => {
24+
expect(validateGs1DataMatrixValue("(01)09501101020917(17)261231(10)ABC123")).toEqual({ valid: true });
25+
});
26+
27+
it("rejects a value that does not start with an Application Identifier", () => {
28+
expect(validateGs1DataMatrixValue("09501101020917").valid).toBe(false);
29+
});
30+
31+
it("rejects an Application Identifier with no data", () => {
32+
expect(validateGs1DataMatrixValue("(01)(17)261231").valid).toBe(false);
33+
});
34+
35+
it("rejects malformed / unbalanced parentheses", () => {
36+
expect(validateGs1DataMatrixValue("(01)09501101020917(17").valid).toBe(false);
37+
});
38+
});

0 commit comments

Comments
 (0)