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

WIP: detect multiple root nodes #25

Merged
merged 5 commits into from
Mar 29, 2020
Merged

Conversation

dobromir-hristov
Copy link
Contributor

@dobromir-hristov dobromir-hristov commented Mar 27, 2020

Description

This PR finds the component's component instance inside the mounted parent vm.
Then adds a property to note if it has multiple root nodes.

This should be then used to aid methods like find or classes as they cannot work with multiple root nodes as of now.

Related to #19

What next?

I need to check whether we can do the same queries from the component's own element, not the mounting parent, even though they should be the same.

Fine Print
This took allot of digging, but I finally got the hang of things 😆

return Array.from(results).map((x) => new DOMWrapper(x))
}

async setChecked(checked: boolean = true) {
return new DOMWrapper(this.vm.$el).setChecked(checked)
return new DOMWrapper(this.element).setChecked(checked)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here it would probably be best to return an error, if the component has multiple roots?

Copy link
Member

Choose a reason for hiding this comment

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

as discussed I think we should omit this code entirely for now and revisit it later - setChecked on a VueWrapper may not make sense after all, I am in favor of only supporting it on DOMWrapper.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK. We can add them back later I guess.

}

trigger(eventString: string) {
const rootElementWrapper = new DOMWrapper(this.vm.$el)
const rootElementWrapper = new DOMWrapper(this.element)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here it would probably be best to return an error, if the component has multiple roots?

Copy link
Member

Choose a reason for hiding this comment

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

See above!

@@ -26,15 +43,15 @@ export class VueWrapper implements WrapperAPI {
}

html() {
return this.vm.$el.outerHTML
return this.element.outerHTML
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can probably do innerHtml for multiple root nodes?

Copy link
Member

Choose a reason for hiding this comment

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

what does outer html return? Whatever makes most sense!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

outerHtml returns the mount point, which is in this case div#app :/

Copy link
Member

Choose a reason for hiding this comment

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

sure, makes sense. I think we need outerHTML for a single node still? (not sure)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct. It will be a check for multiRoot

this.componentVM.$el.parentElement
: this.componentVM.$el
}

classes(): string[] {
throw Error('TODO: Implement VueWrapper#classes')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should error out if classes is used with multiple nodes.

@lmiller1990
Copy link
Member

lmiller1990 commented Mar 28, 2020

Some interesting stuff here. Before getting to into a code review, I have some thoughts:

  • the fact this complexity is introduced, and we might have throw an error if there are multiple nodes feels like a bit of a red flag. Suddenly the users needs to understand the implementation details.

I'm starting to think we should support setChecked etc on VueWrapper, only DOM Wrapper. My reasoning is that components do not get checked or change state - DOM nodes do. We will still need to detect multiple root nodes, either way, so this PR is still useful (eg, for find, we need to apply it on all root node's querySelector somehow).

Take two cases:

Case 1:

<template>
  <input id="foo" type="checkbox" />
</template>

Case 2:

<template>
  <input id="foo" type="checkbox" />
  <input id="bar" type="checkbox" />
</template>

Case 1 wrapper.setChecked works, and case 2 wrapper.setChecked will error out... not ideal.

Should we just remove setChecked (and other methods like trigger) entirely from VueWrapper? As long as we make find work on the root node(s), it will be fine, and I'd argue, a little less magic and more explicit. Then you do:

Case 1: wrapper.find('#foo').setChecked
Case 2: wrapper.find('#foo').setChecked

It's the same for both. Then the user does not need to think about how many root nodes there are, and we don't need to deal with the complexity. You just find your DOM element, and call setChecked. I think it is more intuitive to setChecked on a DOM element as well.

Thoughts? @afontcu and @dobromir-hristov ?

@dobromir-hristov
Copy link
Contributor Author

As most of the times, we just invoke the DOMWrapper methods, it makes sense to remove it from the VueWrapper.
Question is, would we allow find to return a Vue Wrapper, like VTU Beta does now? If so, then its not ideal. If no, then you would rarely invoke setChecked on your own Vue mounted component.

As for find searching in it's root, we would have to use the parent element for searching.
This ofc only works for DOM query selection, and if we introduce more advanced search methods, it would fail. But its a discussion for another ticket :)

@dobromir-hristov dobromir-hristov mentioned this pull request Mar 28, 2020
Copy link
Member

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

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

Left some minor comments, mainly around private on the hasMultipleRoots

src/mount.ts Show resolved Hide resolved
this.__emitted = events
}

get __hasMultipleRoots(): boolean {
Copy link
Member

Choose a reason for hiding this comment

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

instead of using __ we can just make this private and it will only be accessible in the class (and you don't need __ anymore)

private get hasMultipleRoots(): boolean

Copy link
Contributor Author

Choose a reason for hiding this comment

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

alright then

@@ -26,15 +43,15 @@ export class VueWrapper implements WrapperAPI {
}

html() {
return this.vm.$el.outerHTML
return this.element.outerHTML
Copy link
Member

Choose a reason for hiding this comment

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

sure, makes sense. I think we need outerHTML for a single node still? (not sure)

return Array.from(results).map((x) => new DOMWrapper(x))
}

async setChecked(checked: boolean = true) {
return new DOMWrapper(this.vm.$el).setChecked(checked)
return new DOMWrapper(this.element).setChecked(checked)
Copy link
Member

Choose a reason for hiding this comment

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

as discussed I think we should omit this code entirely for now and revisit it later - setChecked on a VueWrapper may not make sense after all, I am in favor of only supporting it on DOMWrapper.

}

trigger(eventString: string) {
const rootElementWrapper = new DOMWrapper(this.vm.$el)
const rootElementWrapper = new DOMWrapper(this.element)
Copy link
Member

Choose a reason for hiding this comment

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

See above!

@dobromir-hristov dobromir-hristov marked this pull request as ready for review March 29, 2020 09:35
@dobromir-hristov
Copy link
Contributor Author

We can remove the other methods in another PR.

@lmiller1990
Copy link
Member

learned a lot from this PR about internals of Vue 3, great!

@lmiller1990 lmiller1990 merged commit 6a21b8c into master Mar 29, 2020
@lmiller1990 lmiller1990 deleted the feat/detect-multiple-root-nodes branch March 29, 2020 09:59
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.

3 participants