forcedotcom / LightningTestingService

Apache License 2.0
122 stars 35 forks source link

Cannot test clicking of elements in component #31

Closed jakeyboi closed 7 years ago

jakeyboi commented 7 years ago

I'm trying to write a test that verifies the correct value displays after a Lightning:button is clicked. Here are the problems:

1) There is no click() method in the aura api. So if I use component.find(), there is no way I can invoke a click action on the button to invoke the function in my controller.

2) I also tried using vanilla js, eg document.getElementById("someId"), but because of Locker Service that returns a Proxy object and I still can't call click() on the element.

In the examples in the test suite in this project, methods from the controller are exposed in the component, which we don't wish to do. We also have a lot of picklists we would like to set without creating a bunch of aura attributes that we don't need to actually make our component work.

I tried switching to an older version of the aura API for my component and test app, but that still did not work.

Is there a work around for being able to click/interact with elements on the component/DOM?

esalman-sfdc commented 7 years ago

LockerService doesn't prevent the test from interacting with DOM within the same locker. Tests run inside org's locker ("c" namespace by default) as they are loaded by the runner component which is at api version 40+ and could access DOM rendered by components from same namespace and at version 40+.

Regarding, 1- Its actually more of a component level design decision rather than aura limitation. For example ui:button had an event 'press' which could be fired programmatically where-as lightning:button has a more streamlined interface probably to reduce complexity.

2- lightning:button is from a different namespace and DOM rendered by it is not part of component api/interface. Thats why LockerService prevents access to it.

In this particular case where the component from another namespace has decided not to expose certain hooks, simplest/sustainable workaround would be to allow tests access to the handler via aura method. Alternatively, lowering the api version of test runner component would enable your test to access lightning:button's DOM but that would have a downside of possibly making your test brittle longterm (as components from other namespace may change their internals).

By the way regarding your comment about pick-lists, are you using lightning:select?

alderete-sfdc commented 7 years ago

I think it's worth thinking about this use case in some detail.

While it sounds like there are work-arounds for simulating a click, we should think about what those work-arounds require customers to add to their code. Are we really saying they need to pollute their components with a bunch of extra code to make them testable, instead of us providing a facility to simulate a click, which might let their tests and components remain more simple?

There are, of course, other approaches to testing the behavior of a component besides clicking it (simulated or whatever) and seeing what happens. And those approaches generally lead to less fragile tests, I suspect. This sounds like a pretty good scenario to write some specific documentation for, including sample code.

Does that sound correct? If so, @esalman-sfdc or @cdengSFDC, could one of you provide me with such a sample? (Or add it to the repo's examples?)

esalman-sfdc commented 7 years ago

@alderete-sfdc such feedback/requirements is great to feed into the roadmap of platform features (components, aura, lockerService etc) given LTS is built on the platform and abides by the same rules as any other application built on the platform. For example, locker service team just added destroy() method to SecureComponentRef as a result of issue reported by LTS consumer and Aura team plans to expose getName() method on Actions.

We can certainly beef-up testing recipes and documentation around such topics though because tests do have to abide by the restrictions/limitations enforced by the platform unless/until they change. This aspect is sort of similar to other frameworks/languages. For example, to unit test a method in a java class, best practice is to allow tests access to it (instead of private at very least mark it package-private)

esalman-sfdc commented 7 years ago

Team owning "lightning:button" has acknowledged the limitation of component's interface and plans to adjust component's interface to allow programmatic interaction.

sjurgis commented 6 years ago

Doesn't wrapping actions into aura:method essentially make them public? If so, isn't that a bit of a security concern?

esalman-sfdc commented 6 years ago

aura:method has access property, so unless you mark the method as global, access is restricted to the namespace. LockerService also doesn't prevent access to DOM elements owned by the namespace. Basically in this particular case, button is rendered by a component from 'lightning' namespace, and the owners of that namespace/component would control what happens when you invoke the method they expose

Tea56 commented 6 years ago

Have you heard from the team owning the "lightning:button" if there is a solution to this?

meanwhile, you recommend using aura:method. could you kindly provide an example of how to mock up the event part of it, i.e. the mouse click, that we can't trigger.

the aura:method will "forward" the call, but i haven't been able to mock up the event param.

This is really a sad scenario, as others have mentioned. Users happen to "click" a lot and if we can't test any of the user interaction, the LTS is not doing much.

Thank you!

KamilSzostak commented 5 years ago

I agree with @Tea56, this is a big limitation. @esalman-sfdc have you heard back from the "lightning:button" owners if the programmatic way to invoke the onClick is already available?

kiaratto commented 5 years ago

have a trick for this. Sample.

on browser console : document.getElementById("sp").childNodes[0].click();