Skip to content

test: add integration tests for ChunkGraph and ChunkGroup integrity#20772

Merged
alexander-akait merged 6 commits intowebpack:mainfrom
aryanraj45:test/graph-integrity
Apr 14, 2026
Merged

test: add integration tests for ChunkGraph and ChunkGroup integrity#20772
alexander-akait merged 6 commits intowebpack:mainfrom
aryanraj45:test/graph-integrity

Conversation

@aryanraj45
Copy link
Copy Markdown
Contributor

Summary

Added integration tests for core graph integrity methods in ChunkGraph.js and lib/ChunkGroup.js. Methods like replaceModule, connectChunkAndModule, and disconnectChunkAndModule were previously hit by high-level tests but had gaps in verifying specific manual manipulation safety during build hooks.

The new suite in test/GraphIntegrity.test.js ensures that graph state remains valid when modules are re-mapped or disconnected within the optimize phase. Standalone coverage for lib/ChunkGraph.js jumped by ~26%.

What kind of change does this PR introduce?

test

Did you add tests for your changes?

Yes, integrated test/GraphIntegrity.test.js.

Does this PR introduce a breaking change?

No.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

N/A.

Use of AI

None

Copilot AI review requested due to automatic review settings April 3, 2026 19:11
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 3, 2026

⚠️ No Changeset found

Latest commit: e8f9e44

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new integration-level test to exercise core ChunkGraph / ChunkGroup graph-manipulation APIs during the compilation.optimize phase, aiming to validate integrity when plugins mutate graph relationships inside build hooks.

Changes:

  • Introduces test/GraphIntegrity.test.js to run a production compilation against test/fixtures and mutate ChunkGraph during optimize.
  • Adds assertions around ChunkGraph.replaceModule, connectChunkAndModule, and disconnectChunkAndModule.
  • Touches ChunkGroup by invoking getChildren() during the same optimization hook.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/GraphIntegrity.test.js Outdated
Comment on lines +32 to +46
chunkGraph.replaceModule(oldModule, newModule);

const hasNew = chunkGraph.isModuleInChunk(newModule, chunk);
const hasOld = chunkGraph.isModuleInChunk(oldModule, chunk);

if (!hasNew || hasOld) {
throw new Error("Module replacement failed in ChunkGraph");
}

chunkGraph.connectChunkAndModule(chunk, oldModule);
chunkGraph.disconnectChunkAndModule(chunk, oldModule);

const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaceModule(oldModule, newModule) replaces a real compilation module with a plain object that is not part of compilation.modules. After this hook, later phases (e.g. chunk hashing via chunk.updateHashchunkGraph.getModuleHash) will try to access hash info for newModule and will throw because no hashes were ever set for it. This makes the test (and potentially the build) fail/flaky. Use an actual Module instance that participates in the compilation (or perform the replace + assertions + full revert within the optimize hook so the compilation continues with a valid graph), and consider calling compilation.checkConstraints() after the mutation to validate integrity.

Suggested change
chunkGraph.replaceModule(oldModule, newModule);
const hasNew = chunkGraph.isModuleInChunk(newModule, chunk);
const hasOld = chunkGraph.isModuleInChunk(oldModule, chunk);
if (!hasNew || hasOld) {
throw new Error("Module replacement failed in ChunkGraph");
}
chunkGraph.connectChunkAndModule(chunk, oldModule);
chunkGraph.disconnectChunkAndModule(chunk, oldModule);
const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();
try {
chunkGraph.replaceModule(oldModule, newModule);
const hasNew = chunkGraph.isModuleInChunk(newModule, chunk);
const hasOld = chunkGraph.isModuleInChunk(oldModule, chunk);
if (!hasNew || hasOld) {
throw new Error("Module replacement failed in ChunkGraph");
}
const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();
}
} finally {
chunkGraph.replaceModule(newModule, oldModule);
chunkGraph.connectChunkAndModule(chunk, oldModule);
chunkGraph.disconnectChunkAndModule(chunk, oldModule);
compilation.checkConstraints();

Copilot uses AI. Check for mistakes.
Comment thread test/GraphIntegrity.test.js Outdated
Comment on lines +21 to +47
const modules = [...chunkGraph.getChunkModulesIterable(chunk)];

if (modules.length >= 1) {
const oldModule = modules[0];
const newModule = {
identifier: () => "mock-module-identifier",
getSourceTypes: () => ["javascript"],
size: () => 0,
identifierIndex: 0
};

chunkGraph.replaceModule(oldModule, newModule);

const hasNew = chunkGraph.isModuleInChunk(newModule, chunk);
const hasOld = chunkGraph.isModuleInChunk(oldModule, chunk);

if (!hasNew || hasOld) {
throw new Error("Module replacement failed in ChunkGraph");
}

chunkGraph.connectChunkAndModule(chunk, oldModule);
chunkGraph.disconnectChunkAndModule(chunk, oldModule);

const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if (modules.length >= 1) guard allows this test to become a no-op (and still pass) if no modules are present or if chunk resolves unexpectedly. Since this is an integration integrity test, it should fail loudly when preconditions aren’t met (e.g., assert a non-empty module list / expected module count) so the test actually validates behavior.

Suggested change
const modules = [...chunkGraph.getChunkModulesIterable(chunk)];
if (modules.length >= 1) {
const oldModule = modules[0];
const newModule = {
identifier: () => "mock-module-identifier",
getSourceTypes: () => ["javascript"],
size: () => 0,
identifierIndex: 0
};
chunkGraph.replaceModule(oldModule, newModule);
const hasNew = chunkGraph.isModuleInChunk(newModule, chunk);
const hasOld = chunkGraph.isModuleInChunk(oldModule, chunk);
if (!hasNew || hasOld) {
throw new Error("Module replacement failed in ChunkGraph");
}
chunkGraph.connectChunkAndModule(chunk, oldModule);
chunkGraph.disconnectChunkAndModule(chunk, oldModule);
const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();
}
if (!chunk) {
throw new Error("Expected compilation to contain at least one chunk");
}
const modules = [...chunkGraph.getChunkModulesIterable(chunk)];
if (modules.length < 1) {
throw new Error("Expected chunk to contain at least one module");
}
const oldModule = modules[0];
const newModule = {
identifier: () => "mock-module-identifier",
getSourceTypes: () => ["javascript"],
size: () => 0,
identifierIndex: 0
};
chunkGraph.replaceModule(oldModule, newModule);
const hasNew = chunkGraph.isModuleInChunk(newModule, chunk);
const hasOld = chunkGraph.isModuleInChunk(oldModule, chunk);
if (!hasNew || hasOld) {
throw new Error("Module replacement failed in ChunkGraph");
}
chunkGraph.connectChunkAndModule(chunk, oldModule);
chunkGraph.disconnectChunkAndModule(chunk, oldModule);
const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix it

Comment thread test/GraphIntegrity.test.js Outdated

const [group] = compilation.chunkGroups;
if (group) {
group.getChildren();
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling group.getChildren() without any assertion doesn’t validate ChunkGroup integrity, and it won’t catch parent/child linkage issues (the method just returns a value). If the goal is integrity checking, use an invariant check (e.g. group.checkConstraints()) or assert expected parent/child relationships so failures are actionable.

Suggested change
group.getChildren();
group.checkConstraints();

Copilot uses AI. Check for mistakes.
@aryanraj45
Copy link
Copy Markdown
Contributor Author

@alexander-akait I have addressed the co-pilot review .can u please take a view Thanks!

Comment thread test/GraphIntegrity.test.js Outdated
});
});
}, 60000);
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is possible to rewrite this test to configCases? You can write a small custom plugin which make the same, I don't like unit tests for such cases because it is hard to maintain and hard to catch the real errors/problems

@aryanraj45
Copy link
Copy Markdown
Contributor Author

@alexander-akait thanks for the suggestion i have completely removed the unit test and migrated the logic to configCases/chunk-graph/graph-integrity.also it increase the line coverage from 26% to 38% Please take a view Thanks

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 10, 2026

Merging this PR will degrade performance by 44.89%

❌ 2 regressed benchmarks
✅ 142 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development","mode":"development"}' 506.8 KB 919.6 KB -44.89%
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 265.9 KB 389 KB -31.65%

Comparing aryanraj45:test/graph-integrity (e8f9e44) with main (a98fd62)

Open in CodSpeed

@alexander-akait
Copy link
Copy Markdown
Member

@aryanraj45 looks good let's fix lint and we can merge

size: () => 0
};

chunkGraph.replaceModule(m, mock);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use // @ts-expect-error for tests comment to avoid types problems

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexander-akait fixed the lint and added the comment please take a view thanks!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please always add for tests, we have an eslint rule that requires to write comment why it is expected

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done please take a look thanks!

@aryanraj45
Copy link
Copy Markdown
Contributor Author

@alexander-akait all the required CI passed!
thanks

@alexander-akait alexander-akait merged commit 5310112 into webpack:main Apr 14, 2026
54 of 55 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (5310112).

Install it locally:

  • npm
npm i -D webpack@https://pkg.pr.new/webpack@5310112
  • yarn
yarn add -D webpack@https://pkg.pr.new/webpack@5310112
  • pnpm
pnpm add -D webpack@https://pkg.pr.new/webpack@5310112

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants