Skip to content
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

HTMLStyleElement.sheet returns null in v16 #1647

Closed
matmannion opened this issue Dec 27, 2024 · 3 comments · Fixed by #1648
Closed

HTMLStyleElement.sheet returns null in v16 #1647

matmannion opened this issue Dec 27, 2024 · 3 comments · Fixed by #1648
Assignees
Labels
bug Something isn't working

Comments

@matmannion
Copy link

matmannion commented Dec 27, 2024

In 16.0.0, calling the following:

const css = 'body { background: red; }'

const styleElement = document.createElement('style')
styleElement.textContent = css
document.body.appendChild(styleElement)

console.log(styleElement.sheet)

Returns null. Before v16, this was returning the same as a browser would; i.e. it allows parsing the CSS rules so they can then be iterated over with styleElement.sheet.cssRules. We use this in our application to scope CSS that comes from (trusted) upstream, and at the moment this is breaking the unit tests.

A full unit test reproducing this, which passes with vitest/happy-dom 15 but fails with happy-dom 16:

import { describe, expect, it } from 'vitest'

const StyleTagRegexp = /<style[^>]*>(?<content>.*?)<\/style>/gis

function getScopedCssRules(html: string, scope: string, dom?: DOMImplementation): string {
  const css = Array.from(html.matchAll(StyleTagRegexp))
    .map(({ groups }) => groups?.content ?? '')
    .join('\n')

  if (!css) {
    return ''
  }

  // Use the browser's CSSOM to parse CSS
  const doc = (dom ?? document.implementation).createHTMLDocument('')
  const styleElement = doc.createElement('style')
  styleElement.textContent = css
  doc.body.appendChild(styleElement)

  return Array.from(styleElement.sheet?.cssRules ?? [])
    .map(rule => {
      if (rule instanceof CSSStyleRule) {
        rule.selectorText = rule.selectorText
          .split(',')
          .map(selector => `${scope} ${selector}`)
          .join(',')
      }

      return rule.cssText
    })
    .join('\n')
}

function scopeCssSelectors(html: string, scope: string, dom?: DOMImplementation): string {
  const scopedCss = getScopedCssRules(html, scope, dom)

  return `${scopedCss ? `<style>${scopedCss}</style>` : ''}${html.replace(StyleTagRegexp, '')}`
}

describe('scopeCssSelectors()', () => {
  it('combines style into a single tag and scopes', () => {
    const html = `
      <style>
        #document h1, #document h2 {
          background: red;
        }
      </style>

      <h1>I love this</h1>

      <STYLE type="text/css">
        h3 {
          color: white;
        }
      </STYLE>
    `

    expect(scopeCssSelectors(html, '.scope'))
      .toEqual(`<style>.scope #document h1,.scope  #document h2 { background: red; }
.scope h3 { color: white; }</style>
      

      <h1>I love this</h1>

      
    `)
  })
})

The test output describes the behaviour in (e.g. 15.11.7). In 16 the <style> tag isn't output at all because it doesn't find any rules.

@matmannion matmannion added the bug Something isn't working label Dec 27, 2024
@capricorn86 capricorn86 self-assigned this Dec 27, 2024
capricorn86 added a commit that referenced this issue Dec 27, 2024
…ng considered as connected to the DOM that was introduced in v16
capricorn86 added a commit that referenced this issue Dec 27, 2024
…ng considered as connected to the DOM that was introduced in v16 (#1648)

* fix: [#1647] Fixes problem with children of created documents not being considered as connected to the DOM that was introduced in v16

* chore: [#1647] Fixes attributeChangedCallback
@capricorn86
Copy link
Owner

capricorn86 commented Dec 27, 2024

Thank you for reporting @matmannion! 🙂

I believe that I have fixed the issue now in v16.0.1.

@matmannion
Copy link
Author

Amazing, can confirm fixed in 16.0.1. Thanks so much @capricorn86

@capricorn86
Copy link
Owner

Great to hear @matmannion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants