org.auraframework.impl.ClientOutOfSyncUITest.java Source code

Java tutorial

Introduction

Here is the source code for org.auraframework.impl.ClientOutOfSyncUITest.java

Source

/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.auraframework.impl;

import org.apache.commons.lang3.StringUtils;
import org.auraframework.Aura;
import org.auraframework.def.ApplicationDef;
import org.auraframework.def.ComponentDef;
import org.auraframework.def.ControllerDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.EventDef;
import org.auraframework.def.HelperDef;
import org.auraframework.def.IncludeDef;
import org.auraframework.def.InterfaceDef;
import org.auraframework.def.LayoutsDef;
import org.auraframework.def.LibraryDef;
import org.auraframework.def.NamespaceDef;
import org.auraframework.def.ProviderDef;
import org.auraframework.def.RendererDef;
import org.auraframework.def.StyleDef;
import org.auraframework.def.ThemeDef;
import org.auraframework.test.WebDriverTestCase;
import org.auraframework.test.annotation.ThreadHostileTest;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.google.common.base.Function;

/**
 * Tests to verify that the client gets updated when we want it to get updated.
 */
public class ClientOutOfSyncUITest extends WebDriverTestCase {

    public ClientOutOfSyncUITest(String name) {
        super(name);
    }

    @Override
    public void perBrowserSetUp() {
        super.perBrowserSetUp();
        // these tests trigger server recompilation which can take a bit of time
        auraUITestingUtil.setTimeoutInSecs(60);
    }

    private DefDescriptor<ComponentDef> setupTriggerComponent(String attrs, String body) {
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String.format(
                baseComponentTag,
                "controller='java://org.auraframework.component.test.java.controller.JavaTestController' " + attrs,
                "<button onclick='{!c.post}'>post</button>" + body));
        DefDescriptor<?> controllerDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc,
                DefDescriptor.JAVASCRIPT_PREFIX, ControllerDef.class);
        addSourceAutoCleanup(controllerDesc,
                "{post:function(c){var a=c.get('c.getString');a.setParams({param:'dummy'});$A.enqueueAction(a);}}");
        return cmpDesc;
    }

    private boolean isIE() {
        switch (getBrowserType()) {
        case IE7:
        case IE8:
        case IE9:
        case IE10:
        case IE11:
            return true;
        default:
            break;
        }
        return false;
    }

    /**
     * Trigger a server action and wait for the browser to begin refreshing.
     */
    private void triggerServerAction() {
        // Careful. Android doesn't like more than one statement.
        auraUITestingUtil.getRawEval("document._waitingForReload = true;");

        // This test flaps on slower environments in IE. Give it a little more time to process the javascript.
        if (isIE()) {
            waitFor(3);
        }
        auraUITestingUtil.findDomElement(By.cssSelector("button")).click();
        if (isIE()) {
            waitFor(3);
        }
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver d) {
                Object ret = auraUITestingUtil.getRawEval("return !document._waitingForReload");
                if (ret != null && ((Boolean) ret).booleanValue()) {
                    return true;
                }
                return false;
            }
        }, timeoutInSecs, "Page failed to refresh after server action triggered.");
        auraUITestingUtil.waitForDocumentReady();
        waitForAuraFrameworkReady();
    }

    public void testGetServerRenderingAfterMarkupChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class,
                String.format(baseComponentTag, "", "hi"));
        String url = getUrl(cmpDesc);
        openNoAura(url);
        assertEquals("hi", getText(By.cssSelector("body")));
        updateStringSource(cmpDesc, String.format(baseComponentTag, "", "bye"));
        // Firefox caches the response so we need to manually include a nonce to effect a reload
        openNoAura(url + "?nonce=" + System.nanoTime());
        auraUITestingUtil.waitForElementText(By.cssSelector("body"), "bye", true);
    }

    @ThreadHostileTest("NamespaceDef modification affects namespace")
    public void testGetClientRenderingAfterStyleChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class,
                String.format(baseComponentTag, "", "<div id='out'>hi</div>"));
        String className = cmpDesc.getNamespace() + StringUtils.capitalize(cmpDesc.getName());
        DefDescriptor<?> styleDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc, DefDescriptor.CSS_PREFIX,
                StyleDef.class);
        addSourceAutoCleanup(styleDesc, String.format(".%s {font-style:italic;}", className));
        addSourceAutoCleanup(Aura.getDefinitionService().getDefDescriptor(
                String.format("%s://%s", DefDescriptor.MARKUP_PREFIX, styleDesc.getNamespace()),
                NamespaceDef.class), "<aura:namespace/>");
        open(cmpDesc);
        assertEquals("italic",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-style"));
        updateStringSource(styleDesc, String.format(".%s {font-style:normal;}", className));
        open(cmpDesc);
        assertEquals("normal",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-style"));
    }

    @ThreadHostileTest("NamespaceDef modification affects namespace")
    public void testGetClientRenderingAfterThemeChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class,
                String.format(baseComponentTag, "", "<div id='out'>hi</div>"));
        String className = cmpDesc.getNamespace() + StringUtils.capitalize(cmpDesc.getName());
        DefDescriptor<?> styleDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc, DefDescriptor.CSS_PREFIX,
                StyleDef.class);
        addSourceAutoCleanup(styleDesc, String.format(".%s {font-size:t(fsize);}", className));
        DefDescriptor<?> themeDesc = Aura.getDefinitionService().getDefDescriptor(String.format("%s://%s:%sTheme",
                DefDescriptor.MARKUP_PREFIX, cmpDesc.getNamespace(), cmpDesc.getNamespace()), ThemeDef.class);
        addSourceAutoCleanup(themeDesc, "<aura:theme><aura:var name='fsize' value='8px'/></aura:theme>");
        open(cmpDesc);
        assertEquals("8px",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-size"));
        updateStringSource(themeDesc, "<aura:theme><aura:var name='fsize' value='66px'/></aura:theme>");
        open(cmpDesc);
        assertEquals("66px",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-size"));
    }

    public void testGetClientRenderingAfterJsControllerChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class,
                String.format(baseComponentTag, "", "<div id='click' onclick='{!c.clicked}'>click</div>"));
        DefDescriptor<?> controllerDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc,
                DefDescriptor.JAVASCRIPT_PREFIX, ControllerDef.class);
        addSourceAutoCleanup(controllerDesc, "{clicked:function(){window.tempVar='inconsequential'}}");
        open(cmpDesc);
        assertNull(auraUITestingUtil.getEval("return window.tempVar;"));
        auraUITestingUtil.findDomElement(By.cssSelector("#click")).click();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver d) {
                return "inconsequential".equals(auraUITestingUtil.getEval("return window.tempVar;"));
            }
        });
        updateStringSource(controllerDesc, "{clicked:function(){window.tempVar='meaningful'}}");
        open(cmpDesc);
        assertNull(auraUITestingUtil.getEval("return window.tempVar;"));
        auraUITestingUtil.findDomElement(By.cssSelector("#click")).click();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver d) {
                return "meaningful".equals(auraUITestingUtil.getEval("return window.tempVar;"));
            }
        });
    }

    public void testGetClientRenderingAfterJsProviderChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = getAuraTestingUtil().createStringSourceDescriptor(null,
                ComponentDef.class, null);
        DefDescriptor<?> providerDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc,
                DefDescriptor.JAVASCRIPT_PREFIX, ProviderDef.class);
        addSourceAutoCleanup(cmpDesc,
                String.format(baseComponentTag,
                        String.format("render='client' provider='%s'", providerDesc.getQualifiedName()),
                        "<aura:attribute name='given' type='string' default=''/>{!v.given}"));
        addSourceAutoCleanup(providerDesc, "({provide:function(){return {attributes:{'given':'silver spoon'}};}})");
        open(cmpDesc);
        assertEquals("silver spoon", getText(By.cssSelector("body")));
        updateStringSource(providerDesc, "({provide:function(){return {attributes:{'given':'golden egg'}};}})");
        open(cmpDesc);
        assertEquals("golden egg", getText(By.cssSelector("body")));
    }

    public void testGetClientRenderingAfterJsHelperChange() throws Exception {
        DefDescriptor<?> helperDesc = addSourceAutoCleanup(HelperDef.class,
                "({getHelp:function(){return 'simply';}})");
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String.format(
                baseComponentTag, String.format("render='client' helper='%s'", helperDesc.getQualifiedName()), ""));
        open(cmpDesc);
        assertEquals("simply", auraUITestingUtil.getEval("return $A.getRoot().getDef().getHelper().getHelp();"));
        updateStringSource(helperDesc, "({getHelp:function(){return 'complicated';}})");
        open(cmpDesc);
        assertEquals("complicated",
                auraUITestingUtil.getEval("return $A.getRoot().getDef().getHelper().getHelp();"));
    }

    public void testGetClientRenderingAfterJsRendererChange() throws Exception {
        DefDescriptor<?> rendererDesc = addSourceAutoCleanup(RendererDef.class,
                "({render:function(){return 'default';}})");
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String
                .format(baseComponentTag, String.format("renderer='%s'", rendererDesc.getQualifiedName()), ""));
        open(cmpDesc);
        assertEquals("default", getText(By.cssSelector("body")));
        updateStringSource(rendererDesc, "({render:function(){return 'custom';}})");
        open(cmpDesc);
        assertEquals("custom", getText(By.cssSelector("body")));
    }

    public void testGetClientRenderingAfterEventChange() throws Exception {
        DefDescriptor<?> eventDesc = addSourceAutoCleanup(EventDef.class,
                "<aura:event type='APPLICATION'><aura:attribute name='explode' type='String' default='pow'/></aura:event>");
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String.format(
                baseComponentTag, "render='client'",
                String.format("<aura:registerevent name='end' type='%s'/>", eventDesc.getDescriptorName())));
        open(cmpDesc);
        assertEquals("pow",
                auraUITestingUtil.getEval(
                        String.format("return $A.getEvt('%s').getDef().getAttributeDefs().explode['default'];",
                                eventDesc.getDescriptorName())));
        updateStringSource(eventDesc,
                "<aura:event type='APPLICATION'><aura:attribute name='explode' type='String' default='kaboom'/></aura:event>");
        open(cmpDesc);
        assertEquals("kaboom",
                auraUITestingUtil.getEval(
                        String.format("return $A.getEvt('%s').getDef().getAttributeDefs().explode['default'];",
                                eventDesc.getDescriptorName())));
    }

    public void testGetServerRenderingAfterInterfaceChange() throws Exception {
        DefDescriptor<?> interfaceDesc = addSourceAutoCleanup(InterfaceDef.class,
                "<aura:interface support='GA' description=''><aura:attribute name='entrance' type='String' default='grand'/></aura:interface>");
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class,
                String.format(baseComponentTag, String.format("implements='%s'", interfaceDesc.getQualifiedName()),
                        "{!v.entrance}"));
        String url = getUrl(cmpDesc);
        openNoAura(url);
        assertEquals("grand", getText(By.cssSelector("body")));
        updateStringSource(interfaceDesc,
                "<aura:interface support='GA' description=''><aura:attribute name='entrance' type='String' default='secret'/></aura:interface>");
        // Firefox caches the response so we need to manually include a nonce to effect a reload
        openNoAura(url + "?nonce=" + System.nanoTime());
        auraUITestingUtil.waitForElementText(By.cssSelector("body"), "secret", true);
    }

    @ThreadHostileTest("LayoutsDef modification affects namespace")
    public void testGetClientRenderingAfterLayoutChange() throws Exception {
        DefDescriptor<ApplicationDef> appDesc = addSourceAutoCleanup(ApplicationDef.class,
                String.format(baseApplicationTag, "", "<div aura:id='xspot'/>"));
        DefDescriptor<?> layoutsDesc = Aura.getDefinitionService().getDefDescriptor(appDesc,
                DefDescriptor.MARKUP_PREFIX, LayoutsDef.class);
        addSourceAutoCleanup(layoutsDesc,
                "<aura:layouts default='def'><aura:layout name='def'><aura:layoutItem container='xspot'>first</aura:layoutItem></aura:layout></aura:layouts>");
        open(appDesc);
        auraUITestingUtil.waitForElementText(By.cssSelector("body"), "first", true);
        updateStringSource(layoutsDesc,
                "<aura:layouts default='def'><aura:layout name='def'><aura:layoutItem container='xspot'>second</aura:layoutItem></aura:layout></aura:layouts>");
        open(appDesc);
        auraUITestingUtil.waitForElementText(By.cssSelector("body"), "second", true);
    }

    public void testGetClientRenderingAfterDependencyChange() throws Exception {
        DefDescriptor<?> depDesc = addSourceAutoCleanup(ComponentDef.class, String.format(baseComponentTag, "",
                "<aura:attribute name='val' type='String' default='initial'/>"));
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class,
                String.format(baseComponentTag, "render='client'",
                        String.format("<aura:dependency resource='%s'/>", depDesc.getQualifiedName())));
        open(cmpDesc);
        assertEquals("initial", auraUITestingUtil.getEval(String.format(
                "return $A.componentService.newComponent('%s').get('v.val');", depDesc.getDescriptorName())));
        updateStringSource(depDesc,
                String.format(baseComponentTag, "", "<aura:attribute name='val' type='String' default='final'/>"));
        open(cmpDesc);
        assertEquals("final", auraUITestingUtil.getEval(String.format(
                "return $A.componentService.newComponent('%s').get('v.val');", depDesc.getDescriptorName())));
    }

    public void testPostAfterMarkupChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent("", "<div id='sample'>free</div>");
        open(cmpDesc);
        assertEquals("free", getText(By.cssSelector("#sample")));
        updateStringSource(cmpDesc,
                String.format(baseComponentTag,
                        "controller='java://org.auraframework.component.test.java.controller.JavaTestController'",
                        "<button onclick='{!c.post}'>post</button><div id='sample'>deposit</div>"));
        triggerServerAction();
        auraUITestingUtil.waitForElementText(By.cssSelector("#sample"), "deposit", true);
    }

    @ThreadHostileTest("NamespaceDef modification affects namespace")
    public void testPostAfterStyleChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent("", "<div id='out'>hi</div>");
        String className = cmpDesc.getNamespace() + StringUtils.capitalize(cmpDesc.getName());
        DefDescriptor<?> styleDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc, DefDescriptor.CSS_PREFIX,
                StyleDef.class);
        addSourceAutoCleanup(styleDesc, String.format(".%s {font-style:italic;}", className));
        addSourceAutoCleanup(Aura.getDefinitionService().getDefDescriptor(
                String.format("%s://%s", DefDescriptor.MARKUP_PREFIX, styleDesc.getNamespace()),
                NamespaceDef.class), "<aura:namespace/>");
        open(cmpDesc);
        assertEquals("italic",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-style"));
        updateStringSource(styleDesc, String.format(".%s {font-style:normal;}", className));
        triggerServerAction();
        auraUITestingUtil.waitForElementFunction(By.cssSelector("." + className),
                new Function<WebElement, Boolean>() {
                    @Override
                    public Boolean apply(WebElement element) {
                        return "normal".equals(element.getCssValue("font-style"));
                    }
                });
    }

    /**
     * A routine to do _many_ iterations of a client out of sync test.
     * 
     * This test really shouldn't be run unless one of the tests is flapping. It lets you iterate a number of times to
     * force a failure.... No guarantees, but without the _waitingForReload check in the trigger function, this will
     * cause a failure in very few iterations.
     */
    @ThreadHostileTest("NamespaceDef modification affects namespace")
    public void _testPostManyAfterStyleChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent("", "<div id='out'>hi</div>");
        String className = cmpDesc.getNamespace() + StringUtils.capitalize(cmpDesc.getName());
        DefDescriptor<?> styleDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc, DefDescriptor.CSS_PREFIX,
                StyleDef.class);
        addSourceAutoCleanup(styleDesc, String.format(".%s {font-style:italic;}", className));
        addSourceAutoCleanup(Aura.getDefinitionService().getDefDescriptor(
                String.format("%s://%s", DefDescriptor.MARKUP_PREFIX, styleDesc.getNamespace()),
                NamespaceDef.class), "<aura:namespace/>");
        open(cmpDesc);
        assertEquals("italic",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-style"));
        for (int i = 0; i < 1000; i++) {
            updateStringSource(styleDesc, String.format(".%s {font-style:normal;}", className));
            triggerServerAction();
            auraUITestingUtil.waitForElementFunction(By.cssSelector("." + className),
                    new Function<WebElement, Boolean>() {
                        @Override
                        public Boolean apply(WebElement element) {
                            return "normal".equals(element.getCssValue("font-style"));
                        }
                    });
            updateStringSource(styleDesc, String.format(".%s {font-style:italic;}", className));
            triggerServerAction();
            auraUITestingUtil.waitForElementFunction(By.cssSelector("." + className),
                    new Function<WebElement, Boolean>() {
                        @Override
                        public Boolean apply(WebElement element) {
                            return "italic".equals(element.getCssValue("font-style"));
                        }
                    });
        }
    }

    @ThreadHostileTest("NamespaceDef modification affects namespace")
    public void testPostAfterThemeChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent("", "<div id='out'>hi</div>");
        String className = cmpDesc.getNamespace() + StringUtils.capitalize(cmpDesc.getName());
        DefDescriptor<?> styleDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc, DefDescriptor.CSS_PREFIX,
                StyleDef.class);
        addSourceAutoCleanup(styleDesc, String.format(".%s {font-size:t(fsize);}", className));
        DefDescriptor<?> themeDesc = Aura.getDefinitionService().getDefDescriptor(String.format("%s://%s:%sTheme",
                DefDescriptor.MARKUP_PREFIX, cmpDesc.getNamespace(), cmpDesc.getNamespace()), ThemeDef.class);
        addSourceAutoCleanup(themeDesc, "<aura:theme><aura:var name='fsize' value='8px'/></aura:theme>");
        open(cmpDesc);
        assertEquals("8px",
                auraUITestingUtil.findDomElement(By.cssSelector("." + className)).getCssValue("font-size"));
        updateStringSource(themeDesc, "<aura:theme><aura:var name='fsize' value='66px'/></aura:theme>");
        triggerServerAction();
        auraUITestingUtil.waitForElementFunction(By.cssSelector("." + className),
                new Function<WebElement, Boolean>() {
                    @Override
                    public Boolean apply(WebElement element) {
                        return "66px".equals(element.getCssValue("font-size"));
                    }
                });
    }

    public void testPostAfterJsControllerChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String.format(
                baseComponentTag,
                "controller='java://org.auraframework.component.test.java.controller.JavaTestController'",
                "<button onclick='{!c.post}'>post</button><div id='click' onclick='{!c.clicked}'>click</div>"));
        DefDescriptor<?> controllerDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc,
                DefDescriptor.JAVASCRIPT_PREFIX, ControllerDef.class);
        addSourceAutoCleanup(controllerDesc,
                "{post:function(c){var a=c.get('c.getString');a.setParams({param:'dummy'});$A.enqueueAction(a);},clicked:function(){window.tempVar='inconsequential'}}");
        open(cmpDesc);
        assertNull(auraUITestingUtil.getEval("return window.tempVar;"));
        auraUITestingUtil.findDomElement(By.cssSelector("#click")).click();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver d) {
                return "inconsequential".equals(auraUITestingUtil.getEval("return window.tempVar;"));
            }
        });
        updateStringSource(controllerDesc,
                "{post:function(c){var a=c.get('c.getString');a.setParams({param:'dummy'});$A.enqueueAction(a);},clicked:function(){window.tempVar='meaningful'}}");
        triggerServerAction();
        // wait for page to reload by checking that our tempVar is undefined again
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                return (Boolean) auraUITestingUtil.getEval("return !window.tempVar;");
            }
        });
        auraUITestingUtil.findDomElement(By.cssSelector("#click")).click();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                return "meaningful".equals(auraUITestingUtil.getEval("return window.tempVar;"));
            }
        });
    }

    public void testPostAfterJsProviderChange() throws Exception {
        DefDescriptor<ComponentDef> cmpDesc = getAuraTestingUtil().createStringSourceDescriptor(null,
                ComponentDef.class, null);
        DefDescriptor<?> providerDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc,
                DefDescriptor.JAVASCRIPT_PREFIX, ProviderDef.class);
        addSourceAutoCleanup(cmpDesc, String.format(baseComponentTag, String.format(
                "controller='java://org.auraframework.component.test.java.controller.JavaTestController' provider='%s'",
                providerDesc.getQualifiedName()),
                "<button onclick='{!c.post}'>post</button><aura:attribute name='given' type='string' default=''/><div id='result'>{!v.given}</div>"));
        DefDescriptor<?> controllerDesc = Aura.getDefinitionService().getDefDescriptor(cmpDesc,
                DefDescriptor.JAVASCRIPT_PREFIX, ControllerDef.class);
        addSourceAutoCleanup(controllerDesc,
                "{post:function(c){var a=c.get('c.getString');a.setParams({param:'dummy'});$A.enqueueAction(a);}}");
        addSourceAutoCleanup(providerDesc, "({provide:function(){return {attributes:{'given':'silver spoon'}};}})");
        open(cmpDesc);
        assertEquals("silver spoon", getText(By.cssSelector("#result")));
        updateStringSource(providerDesc, "({provide:function(){return {attributes:{'given':'golden egg'}};}})");
        triggerServerAction();
        auraUITestingUtil.waitForElementText(By.cssSelector("#result"), "golden egg", true);
    }

    public void testPostAfterJsHelperChange() throws Exception {
        DefDescriptor<?> helperDesc = addSourceAutoCleanup(HelperDef.class,
                "({getHelp:function(){return 'simply';}})");
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent(
                String.format("helper='%s'", helperDesc.getQualifiedName()), "");
        open(cmpDesc);
        assertEquals("simply", auraUITestingUtil.getEval("return $A.getRoot().getDef().getHelper().getHelp();"));
        updateStringSource(helperDesc, "({getHelp:function(){return 'complicated';}})");
        triggerServerAction();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                auraUITestingUtil.waitForDocumentReady();
                auraUITestingUtil.waitForAuraFrameworkReady(null);
                return "complicated".equals(auraUITestingUtil.getEval(
                        "return window.$A && $A.getRoot() && $A.getRoot().getDef().getHelper().getHelp();"));
            }
        });
    }

    public void testPostAfterJsRendererChange() throws Exception {
        DefDescriptor<?> rendererDesc = addSourceAutoCleanup(RendererDef.class,
                "({render:function(){var e=document.createElement('div');e.id='target';e.appendChild(document.createTextNode('default'));var r=this.superRender();r.push(e);return r;}})");
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent(
                String.format("renderer='%s'", rendererDesc.getQualifiedName()), "");
        open(cmpDesc);
        assertEquals("default", getText(By.cssSelector("#target")));
        updateStringSource(rendererDesc,
                "({render:function(){var e=document.createElement('div');e.id='target';e.appendChild(document.createTextNode('custom'));var r=this.superRender();r.push(e);return r;}})");
        triggerServerAction();
        auraUITestingUtil.waitForElementText(By.cssSelector("#target"), "custom", true);
    }

    public void testPostAfterEventChange() throws Exception {
        final DefDescriptor<?> eventDesc = addSourceAutoCleanup(EventDef.class,
                "<aura:event type='APPLICATION'><aura:attribute name='explode' type='String' default='pow'/></aura:event>");
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent("",
                String.format("<aura:registerevent name='end' type='%s'/>", eventDesc.getDescriptorName()));
        open(cmpDesc);
        assertEquals("pow",
                auraUITestingUtil.getEval(
                        String.format("return $A.getEvt('%s').getDef().getAttributeDefs().explode['default'];",
                                eventDesc.getDescriptorName())));
        updateStringSource(eventDesc,
                "<aura:event type='APPLICATION'><aura:attribute name='explode' type='String' default='kaboom'/></aura:event>");
        triggerServerAction();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                auraUITestingUtil.waitForDocumentReady();
                auraUITestingUtil.waitForAuraFrameworkReady(null);
                String eval = String.format(
                        "return ((window.$A && $A.getEvt('%s')) && (window.$A && $A.getEvt('%s')).getDef().getAttributeDefs().explode['default']);",
                        eventDesc.getDescriptorName(), eventDesc.getDescriptorName());
                return "kaboom".equals(auraUITestingUtil.getEval(eval));
            }
        });
    }

    public void testPostAfterInterfaceChange() throws Exception {
        DefDescriptor<?> interfaceDesc = addSourceAutoCleanup(InterfaceDef.class,
                "<aura:interface support='GA' description=''><aura:attribute name='entrance' type='String' default='grand'/></aura:interface>");
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent(
                String.format("implements='%s'", interfaceDesc.getQualifiedName()),
                "<div id='target'>{!v.entrance}</div>");
        open(cmpDesc);
        assertEquals("grand", getText(By.cssSelector("#target")));
        updateStringSource(interfaceDesc,
                "<aura:interface support='GA' description=''><aura:attribute name='entrance' type='String' default='secret'/></aura:interface>");
        triggerServerAction();
        auraUITestingUtil.waitForElementText(By.cssSelector("#target"), "secret", true);
    }

    public void testPostAfterDependencyChange() throws Exception {
        final DefDescriptor<?> depDesc = addSourceAutoCleanup(ComponentDef.class, String.format(baseComponentTag,
                "", "<aura:attribute name='val' type='String' default='initial'/>"));
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent("",
                String.format("<aura:dependency resource='%s'/>", depDesc.getQualifiedName()));
        open(cmpDesc);
        assertEquals("initial",
                auraUITestingUtil.getEval(String.format(
                        "return $A.componentService.getDef('%s').getAttributeDefs().getDef('val').getDefault();",
                        depDesc.getDescriptorName())));
        updateStringSource(depDesc,
                String.format(baseComponentTag, "", "<aura:attribute name='val' type='String' default='final'/>"));
        triggerServerAction();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                auraUITestingUtil.waitForDocumentReady();
                auraUITestingUtil.waitForAuraFrameworkReady(null);
                return "final".equals(auraUITestingUtil.getEval(String.format(
                        "return window.$A && $A.componentService.getDef('%s').getAttributeDefs().getDef('val').getDefault();",
                        depDesc.getDescriptorName())));
            }
        });
    }

    public void testGetClientRenderingAfterIncludeChange() throws Exception {
        DefDescriptor<?> helperDesc = addSourceAutoCleanup(HelperDef.class, "({})");
        DefDescriptor<?> libraryDesc = getAuraTestingUtil().createStringSourceDescriptor(null, LibraryDef.class,
                null);
        DefDescriptor<?> includeDesc = getAuraTestingUtil().createStringSourceDescriptor(null, IncludeDef.class,
                libraryDesc);
        addSourceAutoCleanup(includeDesc, "function(){return 'initialized'}");
        addSourceAutoCleanup(libraryDesc,
                String.format("<aura:library><aura:include name='%s'/></aura:library>", includeDesc.getName()));
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String.format(
                baseComponentTag, String.format("render='client' helper='%s'", helperDesc.getQualifiedName()),
                String.format("<aura:import library='%s' property='mylib'/>", libraryDesc.getDescriptorName())));

        open(cmpDesc);
        assertEquals("initialized", auraUITestingUtil.getEval(
                String.format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeDesc.getName())));

        updateStringSource(includeDesc, "function(){return 'updated'}");

        open(cmpDesc);
        assertEquals("updated", auraUITestingUtil.getEval(
                String.format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeDesc.getName())));
    }

    public void testGetClientRenderingAfterLibraryChange() throws Exception {
        DefDescriptor<?> helperDesc = addSourceAutoCleanup(HelperDef.class, "({})");
        DefDescriptor<?> libraryDesc = getAuraTestingUtil().createStringSourceDescriptor(null, LibraryDef.class,
                null);
        DefDescriptor<?> includeDesc = getAuraTestingUtil().createStringSourceDescriptor(null, IncludeDef.class,
                libraryDesc);
        addSourceAutoCleanup(includeDesc, "function(){return 'firstpick'}");
        DefDescriptor<?> includeOtherDesc = getAuraTestingUtil().createStringSourceDescriptor(null,
                IncludeDef.class, libraryDesc);
        addSourceAutoCleanup(includeOtherDesc, "function(){return 'secondpick'}");
        addSourceAutoCleanup(libraryDesc,
                String.format("<aura:library><aura:include name='%s'/></aura:library>", includeDesc.getName()));
        DefDescriptor<ComponentDef> cmpDesc = addSourceAutoCleanup(ComponentDef.class, String.format(
                baseComponentTag, String.format("render='client' helper='%s'", helperDesc.getQualifiedName()),
                String.format("<aura:import library='%s' property='mylib'/>", libraryDesc.getDescriptorName())));

        open(cmpDesc);
        assertEquals("firstpick", auraUITestingUtil.getEval(
                String.format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeDesc.getName())));

        updateStringSource(libraryDesc, String.format("<aura:library><aura:include name='%s'/></aura:library>",
                includeOtherDesc.getName()));

        open(cmpDesc);
        assertEquals("secondpick", auraUITestingUtil.getEval(
                String.format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeOtherDesc.getName())));
    }

    public void testPostAfterIncludeChange() throws Exception {
        DefDescriptor<?> helperDesc = addSourceAutoCleanup(HelperDef.class, "({})");
        DefDescriptor<?> libraryDesc = getAuraTestingUtil().createStringSourceDescriptor(null, LibraryDef.class,
                null);
        final DefDescriptor<?> includeDesc = getAuraTestingUtil().createStringSourceDescriptor(null,
                IncludeDef.class, libraryDesc);
        addSourceAutoCleanup(includeDesc, "function(){return 'initialized'}");
        addSourceAutoCleanup(libraryDesc,
                String.format("<aura:library><aura:include name='%s'/></aura:library>", includeDesc.getName()));
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent(
                String.format("render='client' helper='%s'", helperDesc.getQualifiedName()),
                String.format("<aura:import library='%s' property='mylib'/>", libraryDesc.getDescriptorName()));

        open(cmpDesc);
        assertEquals("initialized", auraUITestingUtil.getEval(
                String.format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeDesc.getName())));

        updateStringSource(includeDesc, "function(){return 'updated'}");

        triggerServerAction();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                auraUITestingUtil.waitForDocumentReady();
                auraUITestingUtil.waitForAuraFrameworkReady(null);
                return "updated".equals(auraUITestingUtil.getEval(String
                        .format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeDesc.getName())));
            }
        });
    }

    public void testPostAfterLibraryChange() throws Exception {
        DefDescriptor<?> helperDesc = addSourceAutoCleanup(HelperDef.class, "({})");
        DefDescriptor<?> libraryDesc = getAuraTestingUtil().createStringSourceDescriptor(null, LibraryDef.class,
                null);
        DefDescriptor<?> includeDesc = getAuraTestingUtil().createStringSourceDescriptor(null, IncludeDef.class,
                libraryDesc);
        addSourceAutoCleanup(includeDesc, "function(){return 'firstpick'}");
        final DefDescriptor<?> includeOtherDesc = getAuraTestingUtil().createStringSourceDescriptor(null,
                IncludeDef.class, libraryDesc);
        addSourceAutoCleanup(includeOtherDesc, "function(){return 'secondpick'}");
        addSourceAutoCleanup(libraryDesc,
                String.format("<aura:library><aura:include name='%s'/></aura:library>", includeDesc.getName()));
        DefDescriptor<ComponentDef> cmpDesc = setupTriggerComponent(
                String.format("render='client' helper='%s'", helperDesc.getQualifiedName()),
                String.format("<aura:import library='%s' property='mylib'/>", libraryDesc.getDescriptorName()));

        open(cmpDesc);
        assertEquals("firstpick", auraUITestingUtil.getEval(
                String.format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeDesc.getName())));

        updateStringSource(libraryDesc, String.format("<aura:library><aura:include name='%s'/></aura:library>",
                includeOtherDesc.getName()));

        triggerServerAction();
        auraUITestingUtil.waitUntil(new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver input) {
                auraUITestingUtil.waitForDocumentReady();
                auraUITestingUtil.waitForAuraFrameworkReady(null);
                return "secondpick".equals(auraUITestingUtil.getEval(String
                        .format("return $A.getRoot().getDef().getHelper().mylib.%s;", includeOtherDesc.getName())));
            }
        });
    }
}