forcedotcom / LightningTestingService

Apache License 2.0
122 stars 35 forks source link

Is there any way to locate the lightning components and trigger automated actions in it ? #42

Closed Vanathi21 closed 6 years ago

Vanathi21 commented 6 years ago

We are trying hard to locate and handle the lightning components such as lightning:button menu, lightning:button Icon, lightning:select, lightning:tabs , lightning:layouts and trigger automated actions in it. When we try it from the DOM it says "undefined", we suspect that due to the locker services. Is there any way to handle these components. In this sample tests also we don't find any examples for these components locator also. Could any one please guide me on this ?

esalman-sfdc commented 6 years ago

In general, you should be able to assign ids to components using 'aura:id', and find them using cmp.find(). See this. Once found, you interact with the component using its interface (attributes, events, methods).

Locker Service does prevent you from accessing the internals (non global attributes, methods, DOM etc.) if the component is from a different namespace.

In case of 'lightning' namespace components you mention above, current limitation is that those components are not exposing methods to programmatically invoke some of the actions (e.g. click, press etc.) they support.

For example, in case of raw html button, you may attach a handler using 'onclick', and then programmatically invoke it via btn.click(). However, 'lightning:button' has onclick attribute but the corresponding lBtn.click() is not part of its current global interface that would prevent you from invoking the handler by calling click.

I had relayed similar feedback to the owner team in the past. I'll reach out again with the list of 'lightning' namespace component you have provided and request enhancements around programmatic access.

For now, you should be able to work around the limitation by invoking the controller actions directly (e.g. via allowing tests access to them via aura:method on your component). See discussion at https://github.com/forcedotcom/LightningTestingService/issues/31 for more details.

Vanathi21 commented 6 years ago

I have a c:inputtext which is a custom component using ui:inputtext. Tried by setting the value attribute but not get reflected in the UI. can you please share some examples to handle nested components .

Also is there any other way to call the client side controller methods other than aura:method ? And also lightning:buttonIcon is there anyway to trigger onclick() on that ?

esalman-sfdc commented 6 years ago

Can you please share code gist. Setting attributes should work. For example see

lightning:buttonIcon needs to expose click() aura:method for you to call it. I have provided that feedback to the team when owns it. For now, workaround would to expose that controller action on you component via aura:method (with access="public" so that only your namespace will have access to it).

Vanathi21 commented 6 years ago

<c:uiInputText aura:id="ruleid" inputProperty="{!v.rule.name}" requiredFlag="true"></c:uiInputText>

uiInputText.cmp

We tried to find the component by assigning aura:id as you have suggested component.find("auraid").set("v.property", "some text here"); cmp.set("v.property", "some text here"); But there is not change in the UI Could you please suggest some ways to handle the nested components ?
esalman-sfdc commented 6 years ago

I tried something similar and and its working for me. Kindly try comparing your code against this simplified repro.

reproW.cmp

<aura:component>
    <c:repro aura:id="r" property="my value" inputLabel="my label"/>
</aura:component>

repro.cmp

<aura:component >
    <aura:attribute name="property" type="String" default=""/>
    <aura:attribute name="inputLabel" type="String" default=""/>
    <ui:inputText aura:id="inputComponent" label="{!v.inputLabel}" value="{!v.property}" />    
</aura:component>

Test

    describe('c:reproW', function() {
        it("try to repro issue42", function(done) {
            $T.createComponent("c:reproW", {}, true)
            .then(function(component) {
                var repro = component.find("r");
                repro.set("v.property", "your value");
                expect(repro.get("v.property")).toBe("your value");
                done();
            }).catch(function(e) {
                done.fail(e);
            });
        });
    });
AntonMichael commented 6 years ago

Ok Thanks.