google-code-export / gwt-test-utils

Automatically exported from code.google.com/p/gwt-test-utils
1 stars 0 forks source link

GXT 2 Templates Do Not Have Variables Replaced #154

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1.  Use FormLayout.
2.  Test fails trying to locate a node with a class.
3.  Inspect node and see that the template FormLayout uses does not have its 
variable placeholders replaced.

What is the expected output? What do you see instead?
Template should have placeholders replaced with values passed in.

What version of the product are you using? On what operating system?
0.40-SNAPSHOT with GXT 2.2.4.

Please provide any additional information below.
TemplatePatcher doesn't appear to use the values that are passed in to replace 
anything in curly brackets.

I've tried making my own patcher, but I'm not sure how to get a 
JavaScriptObject to something I can get a list of keys out of.  I tried making 
a new JSONObject but that gets nothing and toSource is not implemented, so I 
can't re-parse it.

Original issue reported on code.google.com by ke...@kjordan.net on 31 Jul 2012 at 3:18

GoogleCodeExporter commented 9 years ago

Original comment by gael.laz...@gmail.com on 31 Jul 2012 at 3:21

GoogleCodeExporter commented 9 years ago
Could you please provide a simple unit test with failing assertion(s) ? Since 
I'm not a GXT user, I don't really know where to look... thanks !

Original comment by gael.laz...@gmail.com on 31 Jul 2012 at 6:44

GoogleCodeExporter commented 9 years ago
Sample code:
package com.test;

import org.junit.Test;

import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.Window;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.layout.FormLayout;
import com.google.gwt.user.client.ui.RootPanel;
import com.googlecode.gwt.test.GwtModule;
import com.googlecode.gwt.test.GwtTest;

@GwtModule("com.test.GWT_Test_Utils") public class FormLayoutTest extends 
GwtTest {

    @Test public void formTest() {
        Window window = new Window();
        LayoutContainer formContainer = new LayoutContainer();
        FormLayout layout = new FormLayout();
        formContainer.setLayout(layout);
        TextField<String> field = new TextField<String>();
        field.setName("test");
        field.setFieldLabel("Test");
        formContainer.add(field);
        window.add(formContainer);
        window.render(RootPanel.getBodyElement());
        window.show();
        System.out.println(window.getElement().getInnerHTML());
        System.out.println("Inner HTML: " + formContainer.getElement().getInnerHTML());
    }
}

Libraries added:
gwt-test-utils-0.40-SNAPSHOT
gwt-test-utils-gxt2-0.40-SNAPSHOT
gxt-2.2.4
slf4j-api-1.6.1.jar
javassist-3.12.1.GA
gwt-2.4.0

When run it should get error:

com.googlecode.gwt.test.exceptions.ReflectionException: Error while calling 
method 'protected void com.extjs.gxt.ui.client.widget.Container.onAttach()'
    at com.googlecode.gwt.test.utils.GwtReflectionUtils.callPrivateMethod(GwtReflectionUtils.java:144)
    at com.googlecode.gwt.test.utils.GwtReflectionUtils.callPrivateMethod(GwtReflectionUtils.java:163)
    at com.googlecode.gwt.test.gxt2.internal.patchers.ComponentHelperPatcher.doAttachNative(ComponentHelperPatcher.java:14)
    at com.extjs.gxt.ui.client.widget.ComponentHelper.doAttachNative(ComponentHelper.java)
    at com.extjs.gxt.ui.client.widget.ComponentHelper.doAttach(ComponentHelper.java:21)
    at com.extjs.gxt.ui.client.widget.Container.attachChildren(Container.java:635)
    at com.extjs.gxt.ui.client.widget.Container.onLayoutExcecuted(Container.java:497)
    at com.extjs.gxt.ui.client.widget.Container$1.handleEvent(Container.java:586)
    at com.extjs.gxt.ui.client.widget.Container$1.handleEvent(Container.java:580)
    at com.extjs.gxt.ui.client.event.BaseObservable.callListener(BaseObservable.java:178)
    at com.extjs.gxt.ui.client.event.BaseObservable.fireEvent(BaseObservable.java:86)
    at com.extjs.gxt.ui.client.widget.Layout.layout(Layout.java:116)
    at com.extjs.gxt.ui.client.widget.Container.doLayout(Container.java:351)
    at com.extjs.gxt.ui.client.widget.Container.layout(Container.java:443)
    at com.extjs.gxt.ui.client.widget.LayoutContainer.layout(LayoutContainer.java:246)
    at com.extjs.gxt.ui.client.widget.Container.layout(Container.java:426)
    at com.extjs.gxt.ui.client.widget.LayoutContainer.layout(LayoutContainer.java:241)
    at com.extjs.gxt.ui.client.widget.Window.afterShow(Window.java:948)
    at com.extjs.gxt.ui.client.widget.Window.show(Window.java:924)
    at com.test.FormLayoutTest.formTest(FormLayoutTest.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at com.googlecode.gwt.test.internal.junit.GwtBlockJUnit4ClassRunner.run(GwtBlockJUnit4ClassRunner.java:27)
    at com.googlecode.gwt.test.internal.junit.AbstractGwtRunner.run(AbstractGwtRunner.java:47)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NullPointerException
    at com.extjs.gxt.ui.client.widget.layout.FormLayout.renderField(FormLayout.java:339)
    at com.extjs.gxt.ui.client.widget.layout.FormLayout.renderComponent(FormLayout.java:308)
    at com.extjs.gxt.ui.client.widget.Layout.renderAll(Layout.java:352)
    at com.extjs.gxt.ui.client.widget.Layout.onLayout(Layout.java:318)
    at com.extjs.gxt.ui.client.widget.layout.AnchorLayout.onLayout(AnchorLayout.java:99)
    at com.extjs.gxt.ui.client.widget.layout.FormLayout.onLayout(FormLayout.java:267)
    at com.extjs.gxt.ui.client.widget.Layout.layout(Layout.java:114)
    at com.extjs.gxt.ui.client.widget.Container.doLayout(Container.java:351)
    at com.extjs.gxt.ui.client.widget.Container.layout(Container.java:443)
    at com.extjs.gxt.ui.client.widget.LayoutContainer.layout(LayoutContainer.java:246)
    at com.extjs.gxt.ui.client.widget.Container.layout(Container.java:426)
    at com.extjs.gxt.ui.client.widget.LayoutContainer.layout(LayoutContainer.java:241)
    at com.extjs.gxt.ui.client.widget.Container.onAttach(Container.java:476)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.googlecode.gwt.test.utils.GwtReflectionUtils.callPrivateMethod(GwtReflectionUtils.java:133)
    ... 48 more

This is due to the template not replacing variable placeholders and so it can't 
find a node.  From the FormLayout class:
field.render(target.selectNode(".x-form-el-" + field.getId()).dom);
                                ^--------- Can't find this.

Original comment by ke...@kjordan.net on 31 Jul 2012 at 7:30

GoogleCodeExporter commented 9 years ago
 @PatchMethod
   static Element appendInternal(JavaScriptObject t, Element el, JavaScriptObject values) {
      Element template = t.cast();
      el.setInnerHTML(template.getInnerHTML());

      return el;

   }

The problem is the TemplatePatcher method shown above makes no use of values 
which are used to replace the variable placeholders in the template.  Is there 
a way to convert that JavaScriptObject using something in gwt-test-utils to 
something that can easily get key/value pairs out of?

Original comment by ke...@kjordan.net on 1 Aug 2012 at 3:58

GoogleCodeExporter commented 9 years ago
Got it solved I think (at least for array-based, I'd have to find if or where 
GXT Templates use a non-numeric indexed based placeholder), but this fixes my 
issue:

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

import com.extjs.gxt.ui.client.core.Template;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.Element;
import com.googlecode.gwt.test.internal.utils.PropertyContainer;
import com.googlecode.gwt.test.patchers.PatchClass;
import com.googlecode.gwt.test.patchers.PatchMethod;
import com.googlecode.gwt.test.utils.GwtReflectionUtils;

@PatchClass(Template.class) public class TemplatePatcher {

    @PatchMethod(override = true) static Element appendInternal(final JavaScriptObject t, final Element el, final JavaScriptObject values) {
        Element template = t.cast();
        String templHtml = template.getInnerHTML();
        System.out.println(templHtml);
        PropertyContainer pc = GwtReflectionUtils.getPrivateFieldValue(values, "properties");
        if (pc != null) {
            System.out.println("Got a property container");
            if (pc.contains("GXT_JS_ARRAY_INNER_LIST")) {
                List<Object> array = pc.getObject("GXT_JS_ARRAY_INNER_LIST");
                for (int i = 0; i < array.size(); i++) {
                    Object val = array.get(i);
                    System.out.println(val.toString());
                    System.out.println("Replacing {" + i + "} with " + val.toString());
                    templHtml = templHtml.replaceAll("\\{" + i + "\\}", val.toString());
                    System.out.println(templHtml);
                }
            } else {
                for (Map.Entry<String, Object> entry : pc.entrySet()) {
                    System.out.println("Replacing {" + entry.getKey() + "} with " + entry.getValue().toString());
                    templHtml = templHtml.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue().toString());
                }
            }
        } else {
            System.out.println("No property container set...");
        }
        System.out.println(templHtml);
        el.setInnerHTML(templHtml);
        return el;
    }

    @PatchMethod(override = true) static String applyInternal(final JavaScriptObject t, final JavaScriptObject values) {
        Element template = t.cast();
        String templHtml = template.getInnerHTML();
        System.out.println(templHtml);
        PropertyContainer pc = GwtReflectionUtils.getPrivateFieldValue(values, "properties");
        if (pc != null) {
            System.out.println("Got a property container");
            if (pc.contains("GXT_JS_ARRAY_INNER_LIST")) {
                List<Object> array = pc.getObject("GXT_JS_ARRAY_INNER_LIST");
                for (int i = 0; i < array.size(); i++) {
                    Object val = array.get(i);
                    System.out.println(val.toString());
                    System.out.println("Replacing {" + i + "} with " + val.toString());
                    templHtml = templHtml.replaceAll("\\{" + i + "\\}", val.toString());
                    System.out.println(templHtml);
                }
            } else {
                for (Map.Entry<String, Object> entry : pc.entrySet()) {
                    System.out.println("Replacing {" + entry.getKey() + "} with " + entry.getValue().toString());
                    templHtml = templHtml.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue().toString());
                }
            }
        } else {
            System.out.println("No property container set...");
        }
        System.out.println(templHtml);
        return templHtml;
    }

    @PatchMethod(override = true) static void compile(final Template tem) {
        //
    }

    @PatchMethod(override = true) static JavaScriptObject create(final String html) {
        Element template = Document.get().createDivElement().cast();
        template.setInnerHTML(html);
        return template;
    }

    @PatchMethod(override = true) static String getHtml(final JavaScriptObject t) {
        Element template = t.cast();
        return template.getInnerHTML();
    }

    @PatchMethod(override = true) static Element insertInternal(final String method, final JavaScriptObject t, final Element el, final JavaScriptObject values) {
        Element template = t.cast();
        String templHtml = template.getInnerHTML();
        System.out.println(templHtml);
        PropertyContainer pc = GwtReflectionUtils.getPrivateFieldValue(values, "properties");
        if (pc != null) {
            System.out.println("Got a property container");
            if (pc.contains("GXT_JS_ARRAY_INNER_LIST")) {
                List<Object> array = pc.getObject("GXT_JS_ARRAY_INNER_LIST");
                for (int i = 0; i < array.size(); i++) {
                    Object val = array.get(i);
                    System.out.println(val.toString());
                    System.out.println("Replacing {" + i + "} with " + val.toString());
                    templHtml = templHtml.replaceAll("\\{" + i + "\\}", val.toString());
                    System.out.println(templHtml);
                }
            } else {
                for (Map.Entry<String, Object> entry : pc.entrySet()) {
                    System.out.println("Replacing {" + entry.getKey() + "} with " + entry.getValue().toString());
                    templHtml = templHtml.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue().toString());
                }
            }
        } else {
            System.out.println("No property container set...");
        }
        System.out.println(templHtml);
        el.setInnerHTML(templHtml);
        return el;
    }
}

Original comment by ke...@kjordan.net on 3 Aug 2012 at 2:46

GoogleCodeExporter commented 9 years ago
Thanks for your code, I'll modify the TemplatePatcher :)

Original comment by gael.laz...@gmail.com on 7 Aug 2012 at 5:17

GoogleCodeExporter commented 9 years ago
I just deployed a new 0.40-SNAPSHOT version with a TemplatePatcher based on 
your code. Could you please update to give it a try and post some feedback here 
? Thanks a lot !

Original comment by gael.laz...@gmail.com on 7 Aug 2012 at 5:48

GoogleCodeExporter commented 9 years ago
XTemplates will also need a full patcher.  They're trickier than Template 
though since you can have <tpl> tags that do if conditionals and for loops.

Original comment by ke...@kjordan.net on 14 Sep 2012 at 6:02