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

Custom Element initialisation order is wrong (connectedCalback) #1505

Open
j-o-sh opened this issue Aug 15, 2024 · 0 comments
Open

Custom Element initialisation order is wrong (connectedCalback) #1505

j-o-sh opened this issue Aug 15, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@j-o-sh
Copy link

j-o-sh commented Aug 15, 2024

Describe the bug
I initially commented this on a super old Ticket (#958) but have since dug deeper and think this deserves a newer issue. (I hope you agree 🙏)

The order when the connectedCallback will get called for customElements seems incoherent and is also dependent on the order of when document.body.innerHTML is changed vs. when customElements.define is called.

Things that depend on the parent DOM (like this.closest) seem to only work when the element is defined AFTER it has been set in the html, while other aspects like this.getAttribute seem to only work when the element is defined BEFORE the html is set.

To Reproduce
Steps to reproduce the behavior:

test('Custom Elements should be connected before the connectedCallback is invoked', () => {
    document.body.innerHTML = '<div id="parent"><foo-bar></foo-bar></div>'
    customElements.define('foo-bar', class extends HTMLElement {
        foo = null
        connectedCallback() {
            this.foo = this.closest('#parent')
        }
    })

    // This fails but would passs if the order of `customElements.define` and
    // `document.body.innerHTML = ` would be reversed
    expect(document.querySelector('foo-bar').foo).not.toBeNull()
})

test('Custom Elements should be able to access their own attributes', () => {
    customElements.define('foo-bar', class extends HTMLElement {
        bar = null
        connectedCallback() {
            this.bar = this.getAttribute('something')
        }
    })
    document.body.innerHTML = '<div id="parent"><foo-bar something="baz"></foo-bar></div>'

    // This passes
    expect(document.querySelector('foo-bar')?.getAttribute('something')).toEqual('baz')

    // This fails but would passs if the order of `customElements.define` and
    // `document.body.innerHTML = ` would be reversed
    expect(document.querySelector('foo-bar').bar).toEqual('baz')
})

Expected behavior
The order of defining a custom element and setting the html should not matter. Rather, the element should be known in the dom as an unknown HTMLElement when the html is written before the custom element is defined and known as the custom element after.

The connectedCallback of the custom element should only be invoked after connection to the DOM has completed and parent context as well as attributes, slots and inner context are available to the element.

Screenshots
I wrote two unit tests to illustrate this.

Device:
doesn't matter

Additional context

I could be willing to try and fix this bug if you don't find the time to do it but I would need someone to point me in the right direction. I pocked around a bit in the HappyDOM code but wasn't able to find any relevant section, unfortunatelly.

Hope you'll find the time to look into this. Thanks for an awesome testing library.

Cheers ✌️

@j-o-sh j-o-sh added the bug Something isn't working label Aug 15, 2024
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
Development

No branches or pull requests

1 participant