Skip to content

fix: correct <summary> element behavior#2806

Open
nn-morishita wants to merge 3 commits into
vuejs:mainfrom
nn-morishita:fix/issue-2626-description
Open

fix: correct <summary> element behavior#2806
nn-morishita wants to merge 3 commits into
vuejs:mainfrom
nn-morishita:fix/issue-2626-description

Conversation

@nn-morishita
Copy link
Copy Markdown

This PR addresses #2626.

The issue is that

element behavior is inconsistent with the real browser.

I verified this in a real browser, and the issue still occurs.

Reproduction:
https://stackblitz.com/edit/vitejs-vite-qxxwzrgz?file=src%2Fcomponents%2Ftests%2FDetailsComponent.test.ts

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 5, 2026

Deploy Preview for vue-test-utils-docs ready!

Name Link
🔨 Latest commit edab927
🔍 Latest deploy log https://app.netlify.com/projects/vue-test-utils-docs/deploys/6a009310dcdfa00008682b1a
😎 Deploy Preview https://deploy-preview-2806--vue-test-utils-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Member

@cexbrayat cexbrayat left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

I don't think this is enough though. The PR makes <summary> skip ancestor visibility checks entirely in isElementVisible.
That means a <summary> can be reported visible even when one of its ancestors is hidden (for example display: none), which is a regression because hidden ancestors should make descendants not visible.

pseudo-test to reproduce (did not run it, so maybe it needs tweaking):

it('should consider a summary as hidden when an ancestor is hidden', () => {
  const HiddenAncestorSummary = defineComponent({
    template: `
      <div style="display: none;">
        <details>
          <summary>Summary</summary>
        </details>
      </div>
    `
  })

  const wrapper = mount(HiddenAncestorSummary)
  expect(wrapper.find('summary').isVisible()).toBe(false)
})

I also think the PR treats any <summary> inside a <details> as visible, regardless of structure.
That is too broad: only the primary summary should be visible in a closed <details>. A nested <summary> inside closed details content should remain hidden.

it('should consider a summary as hidden when nested inside closed details content', () => {
  const NestedSummaryInClosedDetails = defineComponent({
    template: `
      <details>
        <summary>Main summary</summary>
        <div>
          <summary>Nested summary</summary>
        </div>
      </details>
    `
  })

  const wrapper = mount(NestedSummaryInClosedDetails)
  const summaries = wrapper.findAll('summary')

  expect(summaries[0].isVisible()).toBe(true)
  expect(summaries[1].isVisible()).toBe(false)
});

@cexbrayat
Copy link
Copy Markdown
Member

@nn-morishita are you still interested in fixing the issue or should we close the PR?

@nn-morishita
Copy link
Copy Markdown
Author

@cexbrayat Sorry for the delayed response. I’ve just pushed a new commit addressing the feedback. I’d appreciate it if you could take a look when you have a chance.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 5, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@vue/test-utils@2806

commit: edab927

)
if (element instanceof HTMLInputElement && element.type === 'hidden') {
return false
}
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.

This change is unrelated to the issue, but an interesting addition. Could you either:

  • add a unit test in this PR
  • remove this change from this PR and open another one with a unit test

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.

As the funciton no longer use attribute checking, maybe rename it to isElementVisible?

Comment thread tests/isVisible.spec.ts
})
expect(wrapper.isVisible()).toBe(false)
})
it('DetailContent should be visible when summary is visible', () => {
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.

the tests are under an unrelated test suite, maybe move them a new test suite:

describe('details and summary elements', () => {
  // test cases here
})

Comment thread tests/isVisible.spec.ts
expect(wrapper.find('details').isVisible()).toBe(true)
expect(wrapper.find('summary').isVisible()).toBe(true)
expect(wrapper.find('div').isVisible()).toBe(false)
})
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.

Maybe add a test case, like:

template: `<details><summary><span>Summary</span></summary><div>Content</div></details>`

expect(wrapper.find('summary span').isVisible()).toBe(true)

return true
}

function isHiddenByClosedDetails<T extends Element>(element: T) {
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.

Maybe add a few lines of jsdoc to explain what this function does

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.

2 participants