Skip to content

internal: fix assertion menu not displayed in the correct location #32172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/app/cypress/e2e/studio/studio.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,29 @@ cy.get('#increment').click();
})
})
})

it('shows the assertions menu for an element inside an invisible wrapper', () => {
launchStudio({ specName: 'spec-w-invisible-wrapper.cy.js' })

cy.getAutIframe().within(() => {
// Show menu
cy.contains('Increment').realClick({
button: 'right',
})

cy.get('.__cypress-studio-assertions-menu').shadow()
.find('.assertions-menu').should('be.visible').should('have.css', 'transform', 'matrix(1, 0, 0, 1, 0, 141)')

// Show submenu
cy.get('.__cypress-studio-assertions-menu').shadow()
.find('.assertion-type-text:first').realHover()

cy.get('.__cypress-studio-assertions-menu').shadow()
.find('.assertion-option')
.contains('Increment')
.should('be.visible')
})
})
})

it('removes pending commands if the page is reloaded', () => {
Expand Down
26 changes: 21 additions & 5 deletions packages/app/src/runner/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,34 @@ export function getSelectorHighlightStyles (elements) {
const borderSize = 2

return elements.map((el) => {
const offset = getOffset(el)
let offset = getOffset(el)
let targetElement = el

if (offset.top === 0 && offset.left === 0 && el.children.length > 0) {
// Try to find the first child with non-zero offset
// This is needed to handle cases where the element is a wrapper that has 0 width and 0 height (for example an <astro-slot>)
// so the highlight styles should be on the children and not the wrapper parent
for (let i = 0; i < el.children.length; i++) {
const childOffset = getOffset(el.children[i])

if (childOffset.top !== 0 || childOffset.left !== 0) {
offset = childOffset
targetElement = el.children[i]
break
}
}
}
Copy link

Choose a reason for hiding this comment

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

Bug: Highlight Styling Fails with Child Elements

The getSelectorHighlightStyles function has two issues: it inconsistently uses element properties, and its child offset detection condition is flawed. When a child element's offset is used for positioning, the function still uses the parent element's dimensions, transform, and z-index, resulting in highlight boxes positioned at the child's location but sized and styled according to the parent. Additionally, the condition offset.top === 0 && offset.left === 0 is too broad, incorrectly triggering the child offset logic for elements legitimately at (0,0) and causing mispositioned highlights.

Fix in Cursor Fix in Web


return {
position: 'absolute',
margin: `0px`,
padding: `0px`,
width: `${el.offsetWidth}px`,
height: `${el.offsetHeight}px`,
width: `${targetElement.offsetWidth}px`,
height: `${targetElement.offsetHeight}px`,
top: `${offset.top - borderSize}px`,
left: `${offset.left - borderSize}px`,
transform: getComputedStyle(el, null).transform,
zIndex: getZIndex(el),
transform: getComputedStyle(targetElement, null).transform,
zIndex: getZIndex(targetElement),
}
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello Studio</title>
</head>

<body>
<script>
let count = 0

function increment() {
count++
document.querySelector('p').innerText = `Count is ${count}`
}
</script>

<h1>Hello, Studio!</h1>
<hr />

<p>Count is 0</p>
<button onclick="increment()" id="increment">
<div style="width: 0; height: 0; display: contents;">
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 2V6M6 4H2" stroke="#5A5F7A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Increment
</div>
</button>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('studio functionality', () => {
it('visits a basic html page with an invisible wrapper', function () {
cy.visit('cypress/e2e/invisible-wrapper.html')
})
})
Loading