Conversation
The bug (SVG transform-origin jumping on initial mount) was fixed in PR #3154, which ensured transformBox: "fill-box" and transformOrigin: "50% 50%" are set before dimensions are measured. The fix was preserved during the motion-dom refactoring. This commit adds targeted E2E tests to prevent regression and closes the issue. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR adds two new files — a React test fixture and a Cypress E2E suite — to provide targeted regression coverage for issue #2949 (SVG Key observations:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["cy.visit('?test=svg-style-on-mount')"] --> B["React mounts svg-style-on-mount.tsx"]
B --> C["useMotionValue(50)\nuseTransform → pathLength / opacity / fill"]
C --> D["motion.path\n(pathLength, opacity, x:10, y:10)"]
C --> E["motion.circle\n(fill)"]
C --> F["motion.rect\n(rotate:45)"]
D --> G["Test 1: transform / transformBox / transformOrigin"]
D --> H["Test 2: pathLength attr / stroke-dasharray / stroke-dashoffset"]
D --> I["Test 3: opacity attr (⚠ window.getComputedStyle fallback)"]
E --> J["Test 4: fill attr non-null"]
F --> K["Test 5: transform / transformBox / transformOrigin"]
style I fill:#ffe0b2,stroke:#e65100
Last reviewed commit: ebccbf8 |
| cy.visit("?test=svg-style-on-mount") | ||
| .get("#path") | ||
| .then(([$path]: any) => { | ||
| // Transform should be applied immediately on mount |
There was a problem hiding this comment.
Use
.should() instead of .then() for assertions
All five test cases use .then() for their assertions, but the rest of the codebase (e.g. svg.ts, animate-style.ts) consistently uses .should(). This is a meaningful difference in Cypress: .should() retries the callback until it passes (subject to the command timeout), giving Cypress's async retry-ability for style assertions that may not be synchronously available on the first tick. .then() runs the callback exactly once with no retry, making these tests potentially flaky if styles are applied asynchronously.
The same issue applies to all five it blocks (lines 18, 35, 49, 62, and 73).
| // Transform should be applied immediately on mount | |
| .should(([$path]: any) => { |
| .get("#path") | ||
| .then(([$path]: any) => { | ||
| // opacity should be 0.5 (useTransform(50, [0,100], [0,1])) | ||
| const opacity = |
There was a problem hiding this comment.
window refers to spec-runner window, not the app window
Inside a Cypress .then() (or .should()) callback, the plain window global resolves to the Cypress spec-runner window, not the tested application's window. Calling window.getComputedStyle($path) on an element from the app iframe may return incorrect results or throw a cross-origin error.
The canonical Cypress pattern is to use cy.window() to obtain the application window:
it("Applies useTransform-derived opacity on SVG path on mount", () => {
cy.visit("?test=svg-style-on-mount")
.get("#path")
.should(([$path]: any) => {
const opacity = $path.getAttribute("opacity")
// framer-motion sets opacity as a native SVG attribute,
// so getAttribute should always return a value here.
expect(parseFloat(opacity)).to.equal(0.5)
})
})If a fallback to computed style is genuinely needed, restructure with cy.window():
cy.window().then((win) => {
const opacity =
$path.getAttribute("opacity") ??
win.getComputedStyle($path).opacity
expect(parseFloat(opacity)).to.equal(0.5)
})
Summary
useTransformBackground
The bug reported in #2949 — SVG transform-origin jumping on initial mount because dimensions aren't measured yet — was already fixed in PR #3154 (merged April 2025). That PR ensured
transformBox: "fill-box"andtransformOrigin: "50% 50%"are set on SVG elements before dimensions are measured. The fix was preserved during the subsequentmotion-domrefactoring.However, the issue was never auto-closed because PR #3154 used
ref: #2949instead ofFixes #2949. This PR adds targeted regression tests and closes the issue.Fixes #2949
Test plan
🤖 Generated with Claude Code