Package org.auraframework.impl.javascript.parser

Source Code of org.auraframework.impl.javascript.parser.JavascriptParserTest

/*
* 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.
*/
/*
* Copyright, 1999-2009, salesforce.com All Rights Reserved Company Confidential
*/
package org.auraframework.impl.javascript.parser;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.auraframework.adapter.ComponentLocationAdapter;
import org.auraframework.def.ActionDef.ActionType;
import org.auraframework.def.ControllerDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.DefDescriptor.DefType;
import org.auraframework.def.Definition;
import org.auraframework.def.RendererDef;
import org.auraframework.def.TestCaseDef;
import org.auraframework.def.TestSuiteDef;
import org.auraframework.impl.AuraImplTestCase;
import org.auraframework.impl.javascript.controller.JavascriptActionDef;
import org.auraframework.impl.javascript.controller.JavascriptControllerDef;
import org.auraframework.impl.javascript.controller.JavascriptPseudoAction;
import org.auraframework.impl.javascript.renderer.JavascriptRendererDef;
import org.auraframework.impl.javascript.testsuite.JavascriptTestCaseDef;
import org.auraframework.impl.javascript.testsuite.JavascriptTestSuiteDef;
import org.auraframework.impl.source.BaseSourceLoader;
import org.auraframework.impl.source.file.FileSourceLoader;
import org.auraframework.impl.source.resource.ResourceSourceLoader;
import org.auraframework.impl.system.DefDescriptorImpl;
import org.auraframework.impl.system.DefinitionImpl;
import org.auraframework.impl.util.AuraImplFiles;
import org.auraframework.instance.Action.State;
import org.auraframework.system.Source;
import org.auraframework.throwable.AuraRuntimeException;
import org.auraframework.throwable.quickfix.DefinitionNotFoundException;
import org.auraframework.throwable.quickfix.InvalidDefinitionException;
import org.auraframework.util.ServiceLocator;
import org.auraframework.util.json.Json;

/**
* This class tests the usage of Javascript to specify Controllers, Renderers and Test suites for Aura Components. The
* Javascript files are parsed using the {@link JavascriptParser} and the corresponding defs are created.
*/
public class JavascriptParserTest extends AuraImplTestCase {
    JavascriptParser parser = JavascriptParser.getInstance();

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

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}.
     */
    public void testParse() throws Exception {
        DefDescriptor<TestSuiteDef> descriptor = DefDescriptorImpl.getInstance(
                "js://test.testJSTestSuite", TestSuiteDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        // Step 1: Parse the source which refers to a simple component with a
        // reference to Javascript test suite
        Definition testSuite = parser.parse(descriptor, source);
        assertTrue(testSuite instanceof JavascriptTestSuiteDef);
        // Step 2: Gold file the Json output of the test suite object
        serializeAndGoldFile(testSuite, "_JSTestSuite");
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. This test case includes these scenarios:
     * <ul>
     * <li>A null source</li>
     * <li>A null Descriptor</li>
     * <li>Trying to create a Source for a Def type while no corresponding js file is present for the component</li>
     * </ul>
     */
    public void testNullCases() throws Exception {
        DefDescriptor<TestSuiteDef> descriptor = DefDescriptorImpl.getInstance(
                "js://test.testNoJSControllers", TestSuiteDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        // Test case 1: Try to create a Source for a component which does not
        // have any javascript associated with it
        // getSource() call is looking for testNoJSControllersTest.js in the
        // component folder
        try {
            parser.parse(descriptor, source);
        } catch (Exception e) {// Expect a file not found Exception
            assertEquals(
                    "Exception must be "
                            + AuraRuntimeException.class.getSimpleName(),
                    AuraRuntimeException.class, e.getClass());
            e.getMessage().contains("testNoJSControllersTest.js");
        }
        // Test case 2: Null source
        try {
            parser.parse(descriptor, null);
            fail("should not load null source");
        } catch (Exception e) {
            checkExceptionFull(e, NullPointerException.class, null);
        }
        // Test Case 3: Null component descriptor
        try {
            parser.parse(null, source);
            fail("should not load null component descriptor");
        } catch (Exception e) {
            checkExceptionFull(e, NullPointerException.class, null);
        }
    }

    /**
     * Having duplicate controller methods What if there are two actions in the javascript controller with the same
     * name.
     */
    public void testDuplicateJSController() throws Exception {
        DefDescriptor<ControllerDef> descriptor = DefDescriptorImpl
                .getInstance("js://test.testDuplicateJSController",
                        ControllerDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        Definition controller = parser.parse(descriptor, source);
        assertTrue(controller instanceof JavascriptControllerDef);
        JavascriptControllerDef obj = (JavascriptControllerDef) controller;
        Map<String, JavascriptActionDef> controllerActions = obj
                .getActionDefs();
        assertTrue(controllerActions.containsKey("functionName"));
        // If we have more than one controller function with same name, the
        // later one will replace the previous one
        assertTrue(controllerActions.size() == 1);
        // Verify the only JavascriptAction Def we have
        JavascriptActionDef jsActionDef = null;
        jsActionDef = controllerActions.get("functionName");
        assertEquals(ActionType.CLIENT, jsActionDef.getActionType());
        String[] jsonres = (Json.serialize(jsActionDef)).split("\"");
        // Verify the second function did replace the first one
        assertEquals("second function didn't survive",
                ":function(component) {var v = 2;},", jsonres[10]);
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a simple Component with a Javascript Controller {@link DefType#CONTROLLER}.
     */
    public void testJSController() throws Exception {

        DefDescriptor<ControllerDef> descriptor = DefDescriptorImpl
                .getInstance("js://test.testJSController", ControllerDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        // STEP 1:
        // Parse and create the ControllerDef object for the component
        Definition controller = parser.parse(descriptor, source);

        // STEP 2:
        // 2.1:Verify the CONTROLLERDEF object
        assertTrue(controller instanceof JavascriptControllerDef);
        // Convert from a generic controller to a Javascript type controller
        JavascriptControllerDef obj = (JavascriptControllerDef) controller;
        // Step 4: Verify properties of JavascriptRenderDef Object
        // OBject that is to be verified: Qualified name,
        assertEquals("unexpected qualifiedName of controller",
                "js://test.testJSController", obj.getDescriptor()
                        .getQualifiedName());

        serializeAndGoldFile(controller, "_JSControllerDef");

        // 2.2: Should be able to create an instance of the client action on
        // the server side, but it's a pseudo action
        try {
            obj.createAction("newAction", new HashMap<String, Object>());
            fail("Should not be able to create an instance of the client action on the server side");
        } catch (Exception e) {// Expect a definition not found Exception
            checkExceptionFull(e, DefinitionNotFoundException.class,
                    "No ACTION named js://test.testJSController/ACTION$newAction found");
        }
        JavascriptPseudoAction action = (JavascriptPseudoAction) obj.createAction("functionName1", null);
        assertEquals(State.ERROR, action.getState());

        // 2.3 Extract the action defs and verify each of them in Step 3
        // Get all the actions defined in the Javascript
        Map<String, JavascriptActionDef> controllerActions = obj
                .getActionDefs();

        // STEP 3:
        // 3.1: Verify the number of ACTIONDEF objects is 2
        assertTrue(controllerActions.size() == 2);
        // 3.2: Verify the name of actiodefs
        assertTrue(controllerActions.containsKey("functionName1"));
        assertTrue(controllerActions.containsKey("functionName2"));

        // 3.3: Verify each JavascriptAction Def
        JavascriptActionDef jsActionDef = null;
        // 3.3.1 Action Def 1
        jsActionDef = controllerActions.get("functionName1");
        // Javascript Controllers are to be called on the Client side
        assertEquals(ActionType.CLIENT, jsActionDef.getActionType());
        // Javascript actions have no return type
        assertNull(jsActionDef.getReturnType());
        // Verify the Serialized form of the objects
        serializeAndGoldFile(controllerActions.get("functionName1"),
                "_actionDef_functionName1");

        // OBject that is to be verified, Qualified name
        assertEquals("unexpected qualifiedName for functionName1",
                "js://test.testJSController/ACTION$functionName1", jsActionDef
                        .getDescriptor().getQualifiedName());

        // 3.3.2 Action Def 2
        jsActionDef = controllerActions.get("functionName2");
        // Javascript Controllers are to be called on the Client side
        assertEquals(ActionType.CLIENT, jsActionDef.getActionType());
        // Javascript actions have no return type
        assertNull(jsActionDef.getReturnType());
        // Verify the Serialized form of the objects
        serializeAndGoldFile(controllerActions.get("functionName2"),
                "_actionDef_functionName2");
        // OBject that is to be verified, Qualified name
        assertEquals("unexpected qualifiedName for functionName2",
                "js://test.testJSController/ACTION$functionName2", jsActionDef
                        .getDescriptor().getQualifiedName());

    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a Nested Component with a Javascript Controller {@link DefType#CONTROLLER}.
     */
    public void testNestedComponent() throws Exception {
        DefDescriptor<ControllerDef> descriptor = DefDescriptorImpl
                .getInstance("js://test.testJSControllerParent",
                        ControllerDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        // STEP 1:
        // Parse and create the ControllerDef object for the component
        Definition controller = parser.parse(descriptor, source);
        // STEP 2:
        // 2.1:Verify the CONTROLLERDEF object
        assertTrue(controller instanceof JavascriptControllerDef);
        // Convert from a generic controller to a Javascript type controller
        JavascriptControllerDef obj = (JavascriptControllerDef) controller;
        // Get all the actions defined in the Javascript
        Map<String, JavascriptActionDef> controllerActions = obj
                .getActionDefs();

        // STEP 3:
        // 3.1: Verify the number of ACTIONDEF objects
        assertTrue(controllerActions.size() == 1);
        // 3.2: Verify the name of ActionDefs
        assertTrue(controllerActions.containsKey("functionName1"));

        // 3.4: Verify each JavascriptAction Def
        JavascriptActionDef jsActionDef = null;
        // 3.4.1 Action Def 1
        jsActionDef = controllerActions.get("functionName1");
        assertEquals(ActionType.CLIENT, jsActionDef.getActionType());
        assertNull(jsActionDef.getReturnType());
        // 3.4.2: Verify the Serialized form of the objects
        serializeAndGoldFile(jsActionDef, "_actionDef_functionName1");

        // OBject that is to be verified, Qualified name
        assertEquals("unexpected qualifiedName of functionName1",
                "js://test.testJSControllerParent/ACTION$functionName1",
                jsActionDef.getDescriptor().getQualifiedName());
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor is referring to a
     * Controller but the Javascript should have had only functions. In this scenario there is a variable declaration
     * which is not expected in a controller file. The JSparser will flag an exception for this.
     *
     * @throws Exception
     */
    public void testInvalidJSController() throws Exception {
        DefDescriptor<ControllerDef> descriptor = DefDescriptorImpl.getInstance("js://test.testInvalidJSController",
                ControllerDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        ControllerDef cd = parser.parse(descriptor, source);
        try {
            cd.validateDefinition();
            fail("Javascript controller must only contain functions");
        } catch (Exception e) {
            this.checkExceptionContains(e, InvalidDefinitionException.class, "Expected ':'");
        }
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor is referring to a
     * Controller but the Javascript should have had only functions. In this scenario, the contents of the js file is a
     * well formatted Json but it contains a string assignment to a map key.
     *
     * @throws Exception
     */
    public void testNonFunctionElementsInJSController() throws Exception {
        DefDescriptor<ControllerDef> descriptor = DefDescriptorImpl
                .getInstance("js://test.testNonFunctionElementsInJSController",
                        ControllerDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        ControllerDef cd = parser.parse(descriptor, source);
        try {
            cd.validateDefinition();
            fail("Javascript controller must only contain functions");
        } catch (Exception e) {
          this.checkExceptionContains(e, InvalidDefinitionException.class,
                            "JsonStreamParseException");
        }
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a simple Component with a Javascript Rederer {@link DefType#RENDERER}.
     *
     * @newTestCase Verify the serialized format of Javascript RendererDef.
     * @hierarchy Aura.Unit Tests.Components.Renderer
     * @priority medium
     * @userStorySyncIdOrName a07B0000000Ekdr
     */
    public void testJSRenderer() throws Exception {
        DefDescriptor<RendererDef> descriptor = DefDescriptorImpl.getInstance(
                "js://test.testJSRenderer", RendererDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        // STEP 1:
        // Parse and create the RedererDef object for the component
        Definition renderer = parser.parse(descriptor, source);

        // STEP 2:Verify the RENDERERDEF object
        assertTrue(renderer instanceof JavascriptRendererDef);
        // Convert from a generic DEFINITION to a Javascript Renderer Definition
        JavascriptRendererDef obj = (JavascriptRendererDef) renderer;
        // Step 3: Gold file the JAvascriptRenderDef
        serializeAndGoldFile(renderer, "_JSRendererDef");
        // Step 4: Verify properties of JavascriptRenderDef Object
        // OBject that is to be verified, Qualified name,
        assertEquals("unexpected qualifiedName of renderer",
                "js://test.testJSRenderer", obj.getDescriptor()
                        .getQualifiedName());
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a simple Component with an invalid Javascript Rederer {@link DefType#RENDERER}. Javascript rederer
     * should have only two actions : render & rerender
     */
    // TODO: W-689596 is a broad bug that would cover this case.
    // Uncommnet the test once validation is added in
    // JavascriptRendererDefHandler.
    public void _testInvalidJSRenderer() throws Exception {
        DefDescriptor<RendererDef> descriptor = DefDescriptorImpl.getInstance(
                "js://test.testInvalidJSRenderer", RendererDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);
        try {
            // Parse and create the RedererDef object for the component
            parser.parse(descriptor, source);
            fail("Javascript renderer should have only two actions : render & rerender");
        } catch (AuraRuntimeException expected) {
            // this test is disabled, update error msg when we enable the test
            checkExceptionStart(expected, AuraRuntimeException.class, null);
        }
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a simple Component with a Javascript test {@link DefType#TESTSUITE}.
     */
    public void testJSTestSuite() throws Exception {

        DefDescriptor<TestSuiteDef> descriptor = DefDescriptorImpl.getInstance(
                "js://test.testJSTestSuite", TestSuiteDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);

        // Step 1: Parse the source which refers to a simple component with a
        // reference to Javascript test suite
        Definition testSuite = parser.parse(descriptor, source);
        assertTrue(testSuite instanceof JavascriptTestSuiteDef);

        // Step 2: Gold file the Json output of the test suite object
        serializeAndGoldFile(testSuite, "_JSTestSuite");

        // Step 3: Verify the properties of the JavascriptTestSuiteDef object
        // OBject that is to be verified, Qualified name,
        assertEquals("unexpected qualifiedName of testSuite",
                "js://test.testJSTestSuite",
                ((JavascriptTestSuiteDef) testSuite).getDescriptor()
                        .getQualifiedName());
        // Step 4: Verify each testCaseDef objects in the test suite object
        List<TestCaseDef> testCases = ((JavascriptTestSuiteDef) testSuite)
                .getTestCaseDefs();
        assertEquals(3, testCases.size());
        for (Object o : testCases.toArray()) {
            assertTrue(o instanceof JavascriptTestCaseDef);
            JavascriptTestCaseDef testCaseDef = (JavascriptTestCaseDef) o;
            Map<String, Object> attributes = testCaseDef.getAttributeValues();
            if (testCaseDef.getName().equals("testHelloWorld")) {
                assertTrue(attributes.size() == 1);
                assertTrue(attributes.containsKey("num"));
                assertEquals("2", attributes.get("num"));
                // OBject that is to be verified, Qualified name
                assertEquals("unexpected qualifiedName of testHelloWorld",
                        "js://test.testJSTestSuite/TESTCASE$testHelloWorld",
                        ((DefinitionImpl<?>) o).getDescriptor()
                                .getQualifiedName());
            } else if (testCaseDef.getName().equals("testHelloWorld2")) {
                assertTrue(attributes.size() == 1);
                assertTrue(attributes.containsKey("num"));
                // Should get the default Attribute value
                assertEquals("5", attributes.get("num"));
                // OBject that is to be verified, Qualified name,
                assertEquals("unexpected qualifiedName of testHelloWorld2",
                        "js://test.testJSTestSuite/TESTCASE$testHelloWorld2",
                        ((DefinitionImpl<?>) o).getDescriptor()
                                .getQualifiedName());
            } else if (testCaseDef.getName().equals("testHelloWorld3")) {
                assertTrue(attributes.size() == 2);
                assertTrue(attributes.containsKey("num"));
                assertEquals("4", attributes.get("num"));
                assertTrue(attributes.containsKey("alpha"));
                assertEquals("A", attributes.get("alpha"));
                // OBject that is to be verified, Qualified name
                assertEquals("unexpected qualifiedName of testHelloWorld3",
                        "js://test.testJSTestSuite/TESTCASE$testHelloWorld3",
                        ((DefinitionImpl<?>) o).getDescriptor()
                                .getQualifiedName());
            } else {
                fail("There should be no other test cases created");
            }

        }
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a simple Component with a Javascript test suite {@link DefType#TESTSUITE}. One of the test cases has
     * no function assigned to them, this should cause an Exception
     */

    public void testJSTestSuiteWithoutAttributes() throws Exception {
        DefDescriptor<TestSuiteDef> descriptor = DefDescriptorImpl.getInstance(
                "js://test.testJSTestSuiteWithoutAttributes",
                TestSuiteDef.class);
        Source<?> source = getJavascriptSourceLoader().getSource(descriptor);

        // Step 1: Parse the source which refers to a simple component with a
        // reference to Javascript test suite
        Definition testSuite = parser.parse(descriptor, source);
        assertTrue(testSuite instanceof JavascriptTestSuiteDef);

        // Step 2: Verify the properties of the JavascriptTestSuiteDef object
        // OBject that is to be verified, Qualified name,
        assertEquals("unexpected qualifiedName of testSuite",
                "js://test.testJSTestSuiteWithoutAttributes",
                ((JavascriptTestSuiteDef) testSuite).getDescriptor()
                        .getQualifiedName());
        // Step 3: Verify each testCaseDef objects in the test suite object
        List<TestCaseDef> testCases = ((JavascriptTestSuiteDef) testSuite)
                .getTestCaseDefs();
        assertEquals(2, testCases.size());
        for (Object o : testCases.toArray()) {
            assertTrue(o instanceof JavascriptTestCaseDef);
            JavascriptTestCaseDef testCaseDef = (JavascriptTestCaseDef) o;
            Map<String, Object> attributes = testCaseDef.getAttributeValues();
            if (testCaseDef.getName().equals("testHelloWorld")) {
                assertTrue(attributes.size() == 1);
                assertTrue(attributes.containsKey("num"));
                assertEquals("2", attributes.get("num"));
                // OBject that is to be verified, Qualified name
                assertEquals(
                        "unexpected qualifiedName of testHelloWorld",
                        "js://test.testJSTestSuiteWithoutAttributes/TESTCASE$testHelloWorld",
                        ((DefinitionImpl<?>) o).getDescriptor()
                                .getQualifiedName());
            } else if (testCaseDef.getName().equals("testHelloWorld3")) {
                assertTrue(attributes.size() == 0);
                // OBject that is to be verified, Qualified name
                assertEquals(
                        "unexpected qualifiedName of testHelloWorld3",
                        "js://test.testJSTestSuiteWithoutAttributes/TESTCASE$testHelloWorld3",
                        ((DefinitionImpl<?>) o).getDescriptor()
                                .getQualifiedName());
            } else {
                fail("There should be no other test cases created");
            }
        }
    }

    /**
     * Test method for {@link JavascriptParser#parse(DefDescriptor, Source)}. The DefDescriptor in this case is
     * referring to a simple Component with a Javascript test suite {@link DefType#TESTSUITE}. One of the test cases has
     * no function assigned to them, this should cause an Exception
     */
    public void testJSTestSuiteWithoutTestFunc() throws Exception {
        assertInvalidTestCase("{testWithString:{test:'empty'}}",
                "testWithString 'test' must be a function or an array of functions");
        assertInvalidTestCase("{testWithObject:{test:{}}}",
                "testWithObject 'test' must be a function or an array of functions");
        assertInvalidTestCase(
                "{testWithMixedArray:{test:[function(){},'oops']}}",
                "testWithMixedArray 'test' must be a function or an array of functions");
        assertInvalidTestCase(
                "{testWithObjectFunction:{test:{inner:function(){}}}}",
                "testWithObjectFunction 'test' must be a function or an array of functions");
    }

    private void assertInvalidTestCase(String suiteContent,
            String expectedMessageStartsWith) throws Exception {
        DefDescriptor<TestSuiteDef> desc = addSourceAutoCleanup(
                TestSuiteDef.class, suiteContent);
        Source<TestSuiteDef> source = getSource(desc);
        try {
            parser.parse(desc, source);
            fail("Invalid testsuite: Every test case should have a function assigned to it");
        } catch (AuraRuntimeException expected) {
            assertTrue(expected.getMessage().startsWith(
                    expectedMessageStartsWith));
        }
    }

    private BaseSourceLoader getJavascriptSourceLoader() {
        if (AuraImplFiles.TestComponents.asFile().exists()) {
            return new FileSourceLoader(
                    AuraImplFiles.TestComponents.asFile());
        } else {
            String pkg = ServiceLocator
                    .get()
                    .get(ComponentLocationAdapter.class,
                            "auraImplTestComponentLocationAdapterImpl")
                    .getComponentSourcePackage();
            return new ResourceSourceLoader(pkg);
        }
    }
}
TOP

Related Classes of org.auraframework.impl.javascript.parser.JavascriptParserTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.