From 10d178bfbcbe4cbbb274d9a13d4aca90c674d321 Mon Sep 17 00:00:00 2001 From: Christian Gonzalez <1581488+christiango@users.noreply.github.com> Date: Fri, 10 Jul 2026 14:09:23 -0400 Subject: [PATCH 1/4] fix: update treemap chunk selection --- .changeset/fix-chunk-selection.md | 5 +++ client/components/ModulesTreemap.jsx | 2 +- test/analyzer.js | 53 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-chunk-selection.md diff --git a/.changeset/fix-chunk-selection.md b/.changeset/fix-chunk-selection.md new file mode 100644 index 00000000..bcd5ee28 --- /dev/null +++ b/.changeset/fix-chunk-selection.md @@ -0,0 +1,5 @@ +--- +"webpack-bundle-analyzer": patch +--- + +Fix the treemap not reflecting chunk checkbox selections. diff --git a/client/components/ModulesTreemap.jsx b/client/components/ModulesTreemap.jsx index 474719f2..dcd2daf6 100644 --- a/client/components/ModulesTreemap.jsx +++ b/client/components/ModulesTreemap.jsx @@ -331,7 +331,7 @@ class ModulesTreemap extends Component { }; handleSelectedChunksChange = (selectedChunks) => { - store.setSelectedSize(selectedChunks); + store.setSelectedChunks(selectedChunks); }; handleMouseLeaveTreemap = () => { diff --git a/test/analyzer.js b/test/analyzer.js index ec05eb5b..0c7958aa 100644 --- a/test/analyzer.js +++ b/test/analyzer.js @@ -125,6 +125,59 @@ describe("Analyzer", () => { }); }); + it("should update the treemap when a chunk is deselected", async () => { + generateReportFrom("with-worker-loader-dynamic-import/stats.json"); + const page = await browser.newPage(); + await page.goto( + url.pathToFileURL(path.resolve(__dirname, "./output/report.html")), + ); + + const { chunkLabel, initialTreemapChunks } = await page.evaluate(() => { + const modulesTreemap = document + .querySelector("#app") + .__k.__k.find( + (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, + ).__c; + + return { + chunkLabel: globalThis.chartData[0].label, + initialTreemapChunks: modulesTreemap.treemap.props.data.map( + (chunk) => chunk.label, + ), + }; + }); + + const checkboxChecked = await page.evaluate((label) => { + const checkboxLabel = [...document.querySelectorAll("label")].find( + (node) => node.textContent.trim().startsWith(`${label} (`), + ); + const checkbox = checkboxLabel.querySelector('input[type="checkbox"]'); + checkbox.click(); + return checkbox.checked; + }, chunkLabel); + + await page.evaluate( + () => + new Promise((resolve) => { + setTimeout(resolve); + }), + ); + + const updatedTreemapChunks = await page.evaluate(() => { + const modulesTreemap = document + .querySelector("#app") + .__k.__k.find( + (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, + ).__c; + + return modulesTreemap.treemap.props.data.map((chunk) => chunk.label); + }); + + expect(checkboxChecked).toBe(false); + expect(initialTreemapChunks).toContain(chunkLabel); + expect(updatedTreemapChunks).not.toContain(chunkLabel); + }); + it("should support stats files with modules inside `chunks` array", async () => { generateReportFrom("with-modules-in-chunks/stats.json"); const chartData = await getChartData(); From c6a7c3f19ce9c8add1da9e84a53ff4ac47e88a85 Mon Sep 17 00:00:00 2001 From: Christian Gonzalez <1581488+christiango@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:07:51 -0400 Subject: [PATCH 2/4] test: make chunk selection test deterministic --- test/analyzer.js | 97 +++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/test/analyzer.js b/test/analyzer.js index 0c7958aa..d0aa97fd 100644 --- a/test/analyzer.js +++ b/test/analyzer.js @@ -128,54 +128,67 @@ describe("Analyzer", () => { it("should update the treemap when a chunk is deselected", async () => { generateReportFrom("with-worker-loader-dynamic-import/stats.json"); const page = await browser.newPage(); - await page.goto( - url.pathToFileURL(path.resolve(__dirname, "./output/report.html")), - ); + try { + await page.goto( + url.pathToFileURL(path.resolve(__dirname, "./output/report.html")), + ); - const { chunkLabel, initialTreemapChunks } = await page.evaluate(() => { - const modulesTreemap = document - .querySelector("#app") - .__k.__k.find( - (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, - ).__c; - - return { - chunkLabel: globalThis.chartData[0].label, - initialTreemapChunks: modulesTreemap.treemap.props.data.map( - (chunk) => chunk.label, - ), - }; - }); + const { chunkLabel, initialTreemapChunks } = await page.evaluate(() => { + const modulesTreemap = document + .querySelector("#app") + .__k.__k.find( + (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, + ).__c; + + return { + chunkLabel: globalThis.chartData[0].label, + initialTreemapChunks: modulesTreemap.treemap.props.data.map( + (chunk) => chunk.label, + ), + }; + }); - const checkboxChecked = await page.evaluate((label) => { - const checkboxLabel = [...document.querySelectorAll("label")].find( - (node) => node.textContent.trim().startsWith(`${label} (`), + const checkboxChecked = await page.evaluate((label) => { + const checkboxLabel = [...document.querySelectorAll("label")].find( + (node) => node.textContent.trim().startsWith(`${label} (`), + ); + const checkbox = checkboxLabel.querySelector('input[type="checkbox"]'); + checkbox.click(); + return checkbox.checked; + }, chunkLabel); + + await page.waitForFunction( + (label) => { + const modulesTreemap = document + .querySelector("#app") + .__k.__k.find( + (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, + ).__c; + + return !modulesTreemap.treemap.props.data.some( + (chunk) => chunk.label === label, + ); + }, + {}, + chunkLabel, ); - const checkbox = checkboxLabel.querySelector('input[type="checkbox"]'); - checkbox.click(); - return checkbox.checked; - }, chunkLabel); - - await page.evaluate( - () => - new Promise((resolve) => { - setTimeout(resolve); - }), - ); - const updatedTreemapChunks = await page.evaluate(() => { - const modulesTreemap = document - .querySelector("#app") - .__k.__k.find( - (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, - ).__c; + const updatedTreemapChunks = await page.evaluate(() => { + const modulesTreemap = document + .querySelector("#app") + .__k.__k.find( + (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, + ).__c; - return modulesTreemap.treemap.props.data.map((chunk) => chunk.label); - }); + return modulesTreemap.treemap.props.data.map((chunk) => chunk.label); + }); - expect(checkboxChecked).toBe(false); - expect(initialTreemapChunks).toContain(chunkLabel); - expect(updatedTreemapChunks).not.toContain(chunkLabel); + expect(checkboxChecked).toBe(false); + expect(initialTreemapChunks).toContain(chunkLabel); + expect(updatedTreemapChunks).not.toContain(chunkLabel); + } finally { + await page.close(); + } }); it("should support stats files with modules inside `chunks` array", async () => { From 9b71e9d830920e64907e960b078c6edfed5ee973 Mon Sep 17 00:00:00 2001 From: Christian Gonzalez <1581488+christiango@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:00:35 -0400 Subject: [PATCH 3/4] test: avoid Preact internals in chunk selection test --- client/viewer.jsx | 4 ++++ test/analyzer.js | 54 +++++++++++++++++++---------------------------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/client/viewer.jsx b/client/viewer.jsx index aa38705c..7db5f362 100644 --- a/client/viewer.jsx +++ b/client/viewer.jsx @@ -5,6 +5,10 @@ import { store } from "./store.js"; import "./viewer.css"; +if (globalThis.webpackBundleAnalyzerTest) { + globalThis.webpackBundleAnalyzerStore = store; +} + // Initializing WebSocket for live treemap updates let ws; try { diff --git a/test/analyzer.js b/test/analyzer.js index d0aa97fd..f8cc2cce 100644 --- a/test/analyzer.js +++ b/test/analyzer.js @@ -129,24 +129,20 @@ describe("Analyzer", () => { generateReportFrom("with-worker-loader-dynamic-import/stats.json"); const page = await browser.newPage(); try { + await page.evaluateOnNewDocument(() => { + globalThis.webpackBundleAnalyzerTest = true; + }); await page.goto( url.pathToFileURL(path.resolve(__dirname, "./output/report.html")), ); - const { chunkLabel, initialTreemapChunks } = await page.evaluate(() => { - const modulesTreemap = document - .querySelector("#app") - .__k.__k.find( - (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, - ).__c; - - return { - chunkLabel: globalThis.chartData[0].label, - initialTreemapChunks: modulesTreemap.treemap.props.data.map( + const { chunkLabel, initialTreemapChunks } = await page.evaluate(() => ({ + chunkLabel: globalThis.chartData[0].label, + initialTreemapChunks: + globalThis.webpackBundleAnalyzerStore.visibleChunks.map( (chunk) => chunk.label, ), - }; - }); + })); const checkboxChecked = await page.evaluate((label) => { const checkboxLabel = [...document.querySelectorAll("label")].find( @@ -158,34 +154,28 @@ describe("Analyzer", () => { }, chunkLabel); await page.waitForFunction( - (label) => { - const modulesTreemap = document - .querySelector("#app") - .__k.__k.find( - (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, - ).__c; - - return !modulesTreemap.treemap.props.data.some( + (label) => + !globalThis.webpackBundleAnalyzerStore.visibleChunks.some( (chunk) => chunk.label === label, - ); - }, + ), {}, chunkLabel, ); - const updatedTreemapChunks = await page.evaluate(() => { - const modulesTreemap = document - .querySelector("#app") - .__k.__k.find( - (vnode) => vnode.__c && vnode.__c.handleSelectedChunksChange, - ).__c; - - return modulesTreemap.treemap.props.data.map((chunk) => chunk.label); - }); + const { selectedChunks, visibleChunks } = await page.evaluate(() => ({ + selectedChunks: + globalThis.webpackBundleAnalyzerStore.selectedChunks.map( + (chunk) => chunk.label, + ), + visibleChunks: globalThis.webpackBundleAnalyzerStore.visibleChunks.map( + (chunk) => chunk.label, + ), + })); expect(checkboxChecked).toBe(false); expect(initialTreemapChunks).toContain(chunkLabel); - expect(updatedTreemapChunks).not.toContain(chunkLabel); + expect(selectedChunks).not.toContain(chunkLabel); + expect(visibleChunks).not.toContain(chunkLabel); } finally { await page.close(); } From 87c6b51e0d1438c5963a17dbcbddb6d4cec14b82 Mon Sep 17 00:00:00 2001 From: Christian Gonzalez <1581488+christiango@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:49:27 -0400 Subject: [PATCH 4/4] test: verify chunk filtering through rendered results --- client/viewer.jsx | 4 ---- test/analyzer.js | 47 ++++++++++++++++++++++------------------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/client/viewer.jsx b/client/viewer.jsx index 7db5f362..aa38705c 100644 --- a/client/viewer.jsx +++ b/client/viewer.jsx @@ -5,10 +5,6 @@ import { store } from "./store.js"; import "./viewer.css"; -if (globalThis.webpackBundleAnalyzerTest) { - globalThis.webpackBundleAnalyzerStore = store; -} - // Initializing WebSocket for live treemap updates let ws; try { diff --git a/test/analyzer.js b/test/analyzer.js index f8cc2cce..1ecf2d2a 100644 --- a/test/analyzer.js +++ b/test/analyzer.js @@ -129,20 +129,24 @@ describe("Analyzer", () => { generateReportFrom("with-worker-loader-dynamic-import/stats.json"); const page = await browser.newPage(); try { - await page.evaluateOnNewDocument(() => { - globalThis.webpackBundleAnalyzerTest = true; - }); await page.goto( url.pathToFileURL(path.resolve(__dirname, "./output/report.html")), ); - const { chunkLabel, initialTreemapChunks } = await page.evaluate(() => ({ - chunkLabel: globalThis.chartData[0].label, - initialTreemapChunks: - globalThis.webpackBundleAnalyzerStore.visibleChunks.map( - (chunk) => chunk.label, - ), - })); + const chunkLabel = await page.evaluate( + () => globalThis.chartData[0].label, + ); + + await page.type('input[placeholder="Enter regexp"]', "."); + await page.keyboard.press("Enter"); + await page.waitForFunction( + (label) => + [ + ...document.querySelectorAll('[class*="foundModulesChunkName"]'), + ].some((node) => node.textContent.trim() === label), + {}, + chunkLabel, + ); const checkboxChecked = await page.evaluate((label) => { const checkboxLabel = [...document.querySelectorAll("label")].find( @@ -155,27 +159,20 @@ describe("Analyzer", () => { await page.waitForFunction( (label) => - !globalThis.webpackBundleAnalyzerStore.visibleChunks.some( - (chunk) => chunk.label === label, - ), + ![ + ...document.querySelectorAll('[class*="foundModulesChunkName"]'), + ].some((node) => node.textContent.trim() === label), {}, chunkLabel, ); - const { selectedChunks, visibleChunks } = await page.evaluate(() => ({ - selectedChunks: - globalThis.webpackBundleAnalyzerStore.selectedChunks.map( - (chunk) => chunk.label, - ), - visibleChunks: globalThis.webpackBundleAnalyzerStore.visibleChunks.map( - (chunk) => chunk.label, - ), - })); + const visibleChunkLabels = await page.$$eval( + '[class*="foundModulesChunkName"]', + (nodes) => nodes.map((node) => node.textContent.trim()), + ); expect(checkboxChecked).toBe(false); - expect(initialTreemapChunks).toContain(chunkLabel); - expect(selectedChunks).not.toContain(chunkLabel); - expect(visibleChunks).not.toContain(chunkLabel); + expect(visibleChunkLabels).not.toContain(chunkLabel); } finally { await page.close(); }