Skip to content

Commit f51a3da

Browse files
test(ui): support complex envinfo & cover N/A cases
1 parent 7778038 commit f51a3da

File tree

2 files changed

+85
-11
lines changed

2 files changed

+85
-11
lines changed

packages/webpack-cli/src/ui-renderer.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,17 +296,22 @@ export function parseEnvinfoSections(raw: string): InfoSection[] {
296296
let current: InfoSection | null = null;
297297

298298
for (const line of raw.split("\n")) {
299-
const sectionMatch = line.match(/^ {2}([^:]+):\s*$/);
299+
const sectionMatch = line.match(/^ {2}([^:\s][^:]+):\s*$/);
300300
if (sectionMatch) {
301301
if (current) sections.push(current);
302302
current = { title: sectionMatch[1].trim(), rows: [] };
303303
continue;
304304
}
305305

306-
const rowMatch = line.match(/^ {4}([^:]+):\s+(.+)$/);
306+
const rowMatch = line.match(/^ {4}([^:]+):\s+(.*)$/);
307307
if (rowMatch && current) {
308-
current.rows.push({ label: rowMatch[1].trim(), value: rowMatch[2].trim() });
309-
continue;
308+
const label = rowMatch[1].trim();
309+
const value = rowMatch[2].trim();
310+
311+
if (value) {
312+
current.rows.push({ label, value });
313+
continue;
314+
}
310315
}
311316

312317
const emptyRowMatch = line.match(/^ {4}([^:]+):\s*$/);

test/api/ui-renderer.test.js

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -591,12 +591,12 @@ describe("renderInfo", () => {
591591
describe("parseEnvinfoSections", () => {
592592
it("returns one section per heading", () => {
593593
const sections = parseEnvinfoSections(ENVINFO_FIXTURE);
594-
expect(sections.map((s) => s.title)).toEqual(["System", "Binaries", "Packages"]);
594+
expect(sections.map((section) => section.title)).toEqual(["System", "Binaries", "Packages"]);
595595
});
596596

597597
it("parses key/value rows correctly", () => {
598598
const sections = parseEnvinfoSections(ENVINFO_FIXTURE);
599-
const system = sections.find((s) => s.title === "System");
599+
const system = sections.find((section) => section.title === "System");
600600
expect(system.rows).toEqual(
601601
expect.arrayContaining([expect.objectContaining({ label: "OS", value: "macOS 14.0" })]),
602602
);
@@ -608,17 +608,86 @@ describe("parseEnvinfoSections", () => {
608608

609609
it("skips sections with no parseable rows", () => {
610610
const sections = parseEnvinfoSections("\n Empty:\n\n Real:\n Key: value\n");
611-
const titles = sections.map((s) => s.title);
611+
const titles = sections.map((section) => section.title);
612612
expect(titles).not.toContain("Empty");
613613
expect(titles).toContain("Real");
614614
});
615615

616+
it("sets value to 'N/A' for a row with no value", () => {
617+
const sections = parseEnvinfoSections("\n Browsers:\n Chrome:\n Node: 20.0.0\n");
618+
const chrome = sections[0].rows.find((row) => row.label === "Chrome");
619+
expect(chrome.value).toBe("N/A");
620+
});
621+
622+
it("attaches a passthrough color function to an N/A row", () => {
623+
const sections = parseEnvinfoSections("\n Browsers:\n Chrome:\n");
624+
const chrome = sections[0].rows.find((row) => row.label === "Chrome");
625+
expect(chrome.color).toBeDefined();
626+
expect(chrome.color("test")).toBe("test");
627+
});
628+
629+
it("does not apply N/A or a color function to a row that has a value", () => {
630+
const sections = parseEnvinfoSections("\n Browsers:\n Node: 20.0.0\n");
631+
const node = sections[0].rows.find((row) => row.label === "Node");
632+
expect(node.value).toBe("20.0.0");
633+
expect(node.color).toBeUndefined();
634+
});
635+
636+
it("handles a section where every row is empty", () => {
637+
const sections = parseEnvinfoSections(
638+
"\n Browsers:\n Chrome:\n Firefox:\n Safari:\n",
639+
);
640+
expect(sections[0].rows).toHaveLength(3);
641+
for (const row of sections[0].rows) {
642+
expect(row.value).toBe("N/A");
643+
expect(row.color("x")).toBe("x");
644+
}
645+
});
646+
647+
it("handles mixed empty and valued rows in the same section", () => {
648+
const sections = parseEnvinfoSections(
649+
"\n Binaries:\n Node: 20.0.0\n Yarn:\n npm: 10.0.0\n pnpm:\n",
650+
);
651+
// eslint-disable-next-line prefer-destructuring
652+
const rows = sections[0].rows;
653+
expect(rows.find((row) => row.label === "Node").value).toBe("20.0.0");
654+
expect(rows.find((row) => row.label === "Yarn").value).toBe("N/A");
655+
expect(rows.find((row) => row.label === "npm").value).toBe("10.0.0");
656+
expect(rows.find((row) => row.label === "pnpm").value).toBe("N/A");
657+
});
658+
659+
it("handles complex output with parentheses, paths, and multiple spaces", () => {
660+
const COMPLEX_FIXTURE = `
661+
System:
662+
OS: macOS 14.0 (23A344)
663+
CPU: (10) arm64 Apple M2 Pro
664+
Memory: 10.23 GB / 32.00 GB
665+
Binaries:
666+
Node: 20.9.0 - /usr/local/bin/node
667+
Yarn: 1.22.19 - ~/.yarn/bin/yarn
668+
npm:
669+
Utilities:
670+
Git: 2.39.3 (Apple Git-145)
671+
`;
672+
673+
const sections = parseEnvinfoSections(COMPLEX_FIXTURE);
674+
const system = sections.find((str) => str.title === "System");
675+
const binaries = sections.find((str) => str.title === "Binaries");
676+
const utilities = sections.find((str) => str.title === "Utilities");
677+
expect(system.rows.find((row) => row.label === "OS").value).toBe("macOS 14.0 (23A344)");
678+
expect(system.rows.find((row) => row.label === "CPU").value).toBe("(10) arm64 Apple M2 Pro");
679+
expect(binaries.rows.find((row) => row.label === "Node").value).toBe(
680+
"20.9.0 - /usr/local/bin/node",
681+
);
682+
expect(binaries.rows.find((row) => row.label === "npm").value).toBe("N/A");
683+
expect(utilities.rows.find((row) => row.label === "Git").value).toBe("2.39.3 (Apple Git-145)");
684+
});
685+
616686
it("should match snapshot", () => {
617687
const sections = parseEnvinfoSections(ENVINFO_FIXTURE);
618-
// strip color functions — not serialisable in snapshots
619-
const serialisable = sections.map((s) => ({
620-
title: s.title,
621-
rows: s.rows.map(({ label, value }) => ({ label, value })),
688+
const serialisable = sections.map((section) => ({
689+
title: section.title,
690+
rows: section.rows.map(({ label, value }) => ({ label, value })),
622691
}));
623692
expect(serialisable).toMatchSnapshot();
624693
});

0 commit comments

Comments
 (0)