Skip to content

refactor(graph): group and test the properties that cannot move to a mixin - #1131

Merged
tbouffard merged 2 commits into
mainfrom
refactor/group_and_test_per_instance_properties
Aug 12, 2026
Merged

refactor(graph): group and test the properties that cannot move to a mixin#1131
tbouffard merged 2 commits into
mainfrom
refactor/group_and_test_per_instance_properties

Conversation

@tbouffard

@tbouffard tbouffard commented Aug 10, 2026

Copy link
Copy Markdown
Member

First implementation step of the plan recorded in ADR 0003 (#1130). No behavior change for library users.

Problem

mixInto installs mixin members on the AbstractGraph prototype. A property with a mutable default declared in a mixin is therefore shared by every graph instance: mutating it on one graph mutates it for all of them. There is no compile error, and until this PR, no failing test either.

AbstractGraph already has a dedicated group for the properties concerned, Variables that should be in the mixins but requiring per-instance initialization. That group was neither complete nor guarded.

Changes

pageFormat and warningImage join the group. Both have exactly that constraint, yet were declared in the generic Variables managed here group, so nothing at the declaration said why they must stay. The source diff is a pure relocation, 20 lines out and the same 20 lines in.

Every property of the group is now covered by a test, in the existing Expect no global state for properties coming from mixins block: two graphs, distinct references, then mutate one and check the other is untouched. Each case also asserts that its own mutation is effective, so a case cannot pass by accident with a mutation that does nothing.

Verified that the tests can actually fail, by temporarily sharing pageFormat between instances the way a mixin would: only that case failed, the other six passed.

The group header now points at these tests, so adding a property there without its case becomes an obvious omission rather than a silent one.

sizeDidChange gets a comment explaining why it cannot be extracted. It sits in EventsMixin but reads container-sizing members only, so it looks like an obvious candidate for a move, and the question would otherwise be re-opened by every contributor who spots the mismatch. AbstractGraph calls it from its constructor, from graphModelChanged and from refresh, none of which can depend on an optional plugin. Written as a plain comment rather than JSDoc on purpose: a reader of the public API has no use for a refactoring constraint.

One consequence worth reviewing

Declaration order drives the order of the child elements produced by the Codec export, so moving the two properties moved their elements in the exported XML. The expected XML of all-graph-classes.test.ts is updated accordingly, and the changelog records it.

This is not breaking: decoding matches elements by their as attribute and is order-independent, existing documents decode identically, and previously exported documents stay valid. It is recorded only for consumers comparing exported XML as text, for instance in golden-file tests.

The changelog entry sits under a new Other Changes heading, since the Unreleased section is documented as holding breaking changes only. Happy to drop it if you would rather keep that section strictly for breaking changes.

Validation

Run locally on Node 24 (.nvmrc): build, test-check, the full suite (505 tests, 60 suites), lint, check:circular-dependencies. All passing.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed graph settings so changes to one graph no longer unintentionally affect other graph instances.
    • Ensured graph-specific page formats and warning images remain independently configurable.
  • Serialization

    • XML exports now place pageFormat and warningImage immediately after options for graphs.
    • XML imports remain compatible regardless of element order.
  • Documentation

    • Updated the changelog with the XML export ordering change.

@tbouffard tbouffard added the refactor Code refactoring label Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 43b7d651-fb20-4790-b36a-f2b5b619b0a2

📥 Commits

Reviewing files that changed from the base of the PR and between a3132d8 and 4c05bdb.

📒 Files selected for processing (4)
  • packages/core/__tests__/view/BaseGraph.test.ts
  • packages/core/__tests__/view/Graph.test.ts
  • packages/core/__tests__/view/no-global-state-for-mixin-properties.ts
  • packages/core/src/view/AbstractGraph.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/view/AbstractGraph.ts

Walkthrough

The change initializes pageFormat and warningImage per graph instance, adds shared regression coverage for mutable graph properties, documents sizeDidChange, and updates XML fixture ordering with an Unreleased changelog entry.

Changes

Graph state and serialization

Layer / File(s) Summary
Per-instance graph state
packages/core/src/view/AbstractGraph.ts, packages/core/src/view/mixin/EventsMixin.ts
pageFormat and warningImage move into per-instance initialization. sizeDidChange receives dependency documentation.
Shared graph state regression tests
packages/core/__tests__/view/no-global-state-for-mixin-properties.ts, packages/core/__tests__/view/Graph.test.ts, packages/core/__tests__/view/BaseGraph.test.ts
A shared suite verifies that mutable mixin properties do not leak between Graph and BaseGraph instances.
XML serialization order
packages/core/__tests__/serialization/codec/all-graph-classes.test.ts, CHANGELOG.md
The XML fixture places pageFormat and warningImage before the graph model. The changelog records the ordering and order-independent decoding.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • maxGraph/maxGraph#879: Continues the mixin-state refactor by moving graph properties into per-instance initialization.
  • maxGraph/maxGraph#1078: Extends the Graph and BaseGraph mixin-state tests with a shared isolation suite.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the refactor and testing of graph properties that cannot move into mixins.
Description check ✅ Passed The description provides a detailed problem statement, implementation summary, issue reference, consequences, and validation results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…mixin

mixInto installs mixin members on the AbstractGraph prototype, so a property with a mutable default declared in a mixin
would be shared by every graph instance: mutating it on one graph would mutate it for all of them, with no compile error
and no failing test to signal it. AbstractGraph already has a dedicated group for the properties concerned, but the
group was neither complete nor guarded.

Move pageFormat and warningImage into it. Both have exactly that constraint, yet were declared in the generic "Variables
managed here" group, so nothing at the declaration said why they must stay.

Cover every property of the group with the same data-driven test: two graphs, distinct references, then mutate one and
check the other is untouched. Each case also asserts that its own mutation is effective, so a case cannot pass by
accident with a mutation that does nothing. Verified by temporarily sharing pageFormat between instances: only that case
fails, the others still pass. The group header now points at these tests, so adding a property without its case becomes
an obvious omission rather than a silent one.

Document why sizeDidChange cannot be extracted while at it. It sits in EventsMixin but reads container-sizing members
only, so it looks like an obvious candidate for a move, and the question would otherwise be re-opened by every
contributor who spots the mismatch. AbstractGraph calls it from its constructor, from graphModelChanged and from
refresh, none of which can depend on an optional plugin. Written as a plain comment rather than JSDoc on purpose, a
reader of the public API has no use for a refactoring constraint.

Declaration order drives the order of the child elements produced by the Codec export, so the expected XML of the
all-graph-classes serialization test is updated and the changelog records the change. It is not breaking, decoding
matches elements by their "as" attribute, but consumers comparing exported XML as text will see a diff.
@redfish4ktc
redfish4ktc force-pushed the refactor/group_and_test_per_instance_properties branch from b170d25 to a3132d8 Compare August 11, 2026 13:31
…eGraph

BaseGraph.test.ts and Graph.test.ts each checked that the properties coming from the mixins are not shared between
graph instances, with two diverging copies of the same suite. BaseGraph used hand-written tests that omitted
pageFormat and warningImage and relied on deep inequality, while Graph used a data-driven table that also asserts the
mutation took effect, so that a leak cannot pass unnoticed.

The properties under test are declared on AbstractGraph, so the guarantee is identical for every concrete
implementation. Keeping two copies meant a new property had to be added twice, and in practice it was added only to
one of them.

Extract the table and its assertions into describeNoGlobalStateForMixinProperties(), a suite factory parameterized by
a graph factory, and call it from both files. selectionModel joins the table as its read/mutate/signature shape fits.
The helper is a plain .ts file, so Jest does not collect it as a suite of its own.
@sonarqubecloud

Copy link
Copy Markdown

@tbouffard
tbouffard merged commit 34a0d3c into main Aug 12, 2026
14 checks passed
@tbouffard
tbouffard deleted the refactor/group_and_test_per_instance_properties branch August 12, 2026 04:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants