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

Jest 26 cannot test Web Components #11009

Closed
BlackGlory opened this issue Jan 16, 2021 · 4 comments
Closed

Jest 26 cannot test Web Components #11009

BlackGlory opened this issue Jan 16, 2021 · 4 comments

Comments

@BlackGlory
Copy link
Contributor

Since jsdom 16 adds support to custom elements, this PR also enables users to test their custom web components like this:

import MyCustomElement from './MyCustomElement'

describe('Playlist', () => {
    beforeEach(() => {
        window.customElements.define('my-custom-element', MyCustomElement)
    })

    it('attributes are empty by default', () => {
        const customElement = document.createElement('my-custom-element')
        
        customElement.setAttribute('title', 'My Custom Title')

        expect(customElement.shadowRoot.querySelector('.title').innerHTML).toBe('My Custom Title')
    })
})

Originally posted by @vibaiher in #9606 (comment)

I tried to reproduce this code (pls ignore "!", it is TypeScript):

import { LitElement, html } from 'lit-element'

class MyCustomElement extends LitElement {
  render() {
    return html`<div class="title">My Custom Title</div>`
  }
}

describe('Playlist', () => {
    beforeEach(() => {
        window.customElements.define('my-custom-element', MyCustomElement)
    })

    it('attributes are empty by default', () => {
        const customElement = document.createElement('my-custom-element')!

        expect(customElement.shadowRoot!.querySelector('.title')!.innerHTML).toBe('My Custom Title')
    })
})

and this is the result:

TypeError: Cannot read property 'innerHTML' of null

      15 |         const customElement = document.createElement('my-custom-element')!
      16 | 
    > 17 |         expect(customElement.shadowRoot!.querySelector('.title')!.innerHTML).toBe('My Custom Title')
         |                                                                  ^
      18 |     })
      19 | })
      20 | 

      at Object.<anonymous> (__tests__/test.spec.ts:17:66)
@BlackGlory
Copy link
Contributor Author

No longer use LitElement and TypeScript, get exactly the same result.

class MyCustomElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' })
  }

  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <div class="title">My Custom Title</div>
    `
  }
}

describe('Playlist', () => {
  it('attributes are empty by default', () => {
    window.customElements.define('my-custom-element', MyCustomElement)
    const customElement = document.createElement('my-custom-element')

    expect(customElement.shadowRoot.querySelector('.title').innerHTML).toBe('My Custom Title')
  })
})
    TypeError: Cannot read property 'innerHTML' of null

      17 |     const customElement = document.createElement('my-custom-element')
      18 | 
    > 19 |     expect(customElement.shadowRoot.querySelector('.title').innerHTML).toBe('My Custom Title')
         |            ^
      20 |   })
      21 | })
      22 | 

      at Object.<anonymous> (__tests__/test.spec.js:19:12)

@ahnpnl
Copy link
Contributor

ahnpnl commented Jan 17, 2021

Do you have a reproduce repo ? It is required in the bug template to let others easily help.

@BlackGlory
Copy link
Contributor Author

BlackGlory commented Jan 17, 2021

I found the reason, the example is wrong. Use the following code, it can pass the test.

class MyCustomElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' })
  }

  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <div class="title">My Custom Title</div>
    `
  }
}

window.customElements.define('my-custom-element', MyCustomElement)

test('test', () => {
  document.body.innerHTML = '<my-custom-element></my-custom-element>'

  const element = document.querySelector('my-custom-element')

  expect(element.shadowRoot.querySelector('.title').innerHTML).toBe('My Custom Title')
})

Although I still can't get the LitElement version to pass the test, it may be another issue.
LitElement version:

import { LitElement, html } from 'lit-element'

class MyCustomElement extends LitElement {
  render() {
    return html`<div class="title">My Custom Title</div>`
  }
}

window.customElements.define('my-custom-element', MyCustomElement)

test('test', async () => {
  document.body.innerHTML = '<my-custom-element></my-custom-element>'

  const element = document.querySelector('my-custom-element')

  await Promise.resolve()
  expect(element!.shadowRoot!.querySelector('.title')!.innerHTML).toBe('My Custom Title')
})

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants