You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@wicket.apache.org by Guido Helmers <gu...@gmail.com> on 2009/03/17 22:40:20 UTC

DataTable testability - RepeatingView.childIdCounter not reset after a page refresh

Hi,

(Wicket 1.3.5 / Java 1.6)

I have a page with a DefaultDataTable containing an AjaxFallbackLink in one
of its columns. When the page is rendered for the first time, the link in
row 1 has component id path "table:rows:1:cells:3:cell". When I click this
link while Ajax is disabled, the page is refreshed, and now the link in row
1 (which is still displaying exactly the same item) has changed to
"table:rows:3:cells:3:cell" (my table has 2 rows, hence the row id increase
from 1 to 3). A sample page and unit test can be found at the bottom of this
email (I provided a complete package, including WebApplication and markup
page).

In my data table tests I would like to refer to data table rows and cells by
their component id paths (see DataTablePageTest.java). Currently my tests
are not very robust, because the component id paths of the DataTable rows
and cells vary over time and depend on the page size and number of items
displayed (if page size = 2, after a click, row id 1 has suddenly become 1 +
2 = 3).

The reason that in case of no ajax the row ids increase, is that on a page
refresh the DataGridView.onPopulate() is called, and if you look in
RefreshingView.onPopulate() -> newItemFactory() you will see that a new
child id is retrieved for every item. Because childIdCounter is a private
field of RepeatingView, and the counter is never reset to 0, my row #1 has
suddenly become row #3.

So I'm wondering:
* Is there trick to reset the counter on a page refresh and what side
effects will it have? (RepeatingView.childIdCounter is private and there are
no public/protected methods to influence the counter so I have no idea how
to do it).
* Does anyone have suggestions to improve the below code / unit test, so
that table rows and table cells can be referenced (in the unit test) by a
constant identifier that does not depend on the page size and that doesn't
change over time?

Cheers,
Guido


*_______________
MyWebApplication.java
*
package wicket;

import org.apache.wicket.protocol.http.WebApplication;

public class MyWebApplication extends WebApplication {

    @Override
    public Class getHomePage() {
        return DataTablePage.class;
    }
}



*_______________
MyItem.java
*
package wicket;

import java.io.Serializable;

public class MyItem implements Serializable {

    private static final long serialVersionUID = 1L;

    private String code;

    private String description;

    public MyItem(String code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }
}



*_______________
MyDataProvider.java
*
package wicket;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import nl.rotterdam.ioo.pzr.midoffice.domain.search.SortParams;

import
org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

public class MyDataProvider extends SortableDataProvider {

    private static final long serialVersionUID = 1L;

    private static List<MyItem> items = new ArrayList<MyItem>();
    static {
        items.add(new MyItem("CODE1", "description1"));
        items.add(new MyItem("CODE2", "description2"));
    }

    protected SortParams sortParams;

    public void setQueryParam(SortParams sortParams) {
        this.sortParams = sortParams;
    }

    public MyDataProvider() {
    }

    public Iterator<?> iterator(int first, int count) {
        return items.iterator();
    }

    public IModel model(Object object) {
        return new Model((MyItem) object);
    }

    public int size() {
        return items.size();
    }
}


*_______________
DataTablePage.java
*
package wicket;

import java.util.Arrays;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import
org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import
org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import
org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

public class DataTablePage extends WebPage {

    private final DefaultDataTable table;

    public DataTablePage() {

        MyDataProvider dataProvider = new MyDataProvider();
        IColumn[] columns = new IColumn[3];

        columns[0] = new PropertyColumn(new Model("Code"), "code", "code");
        columns[1] = new PropertyColumn(new Model("Description"),
"description");
        columns[2] = new AbstractColumn(new Model("Select")) {
            private static final long serialVersionUID = 1L;

            public void populateItem(Item cellItem, String componentId,
IModel rowModel) {
                final MyItem item = (MyItem) rowModel.getObject();
                AjaxFallbackLink link = new AjaxFallbackLink(componentId) {
                    @Override
                    public void onClick(AjaxRequestTarget target) {
                        System.out.println("Click item " + item.getCode() +
" with target=" + target);
                    }
                };
                cellItem.add(link);
            }
        };

        table = new DefaultDataTable("table", Arrays.asList(columns),
dataProvider, 10);
        add(table);
    }
}


*_______________
DataTablePage.html
*
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="
http://wicket.apache.org/" xml:lang="nl" lang="nl">
<head>
    <title>DataTable test page</title>
</head>
<body>
    <table wicket:id="table"></table>
</body>
</html>


*_______________
DataTablePageTest.java
*
package wicket;

import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.util.tester.WicketTester;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class DataTablePageTest {

    private WicketTester tester;

    @Before
    public void setUp() throws Exception {
        MyWebApplication application = new MyWebApplication();
        tester = new WicketTester(application);
    }

    @After
    public void tearDown() throws Exception {
        tester.destroy();
    }

    @Test
    public void testWithAjax() {
        test(true);
    }

    @Test
    public void testWithoutAjax() {
        test(false);
    }

    private void test(boolean ajax) {
        String pathToLinkInRow1 = "table:rows:1:cells:3:cell";

        tester.startPage(DataTablePage.class);
        tester.assertRenderedPage(DataTablePage.class);

        //tester.debugComponentTrees();
        tester.clickLink(pathToLinkInRow1, ajax);
        //tester.debugComponentTrees();

        // the following assertion fails if ajax=false
        tester.assertComponent(pathToLinkInRow1, AjaxFallbackLink.class);
    }
}

Re: DataTable testability - RepeatingView.childIdCounter not reset after a page refresh

Posted by Igor Vaynberg <ig...@gmail.com>.
in the test you can always associate metadata with any component you
want to identify it later. or for simple scenarios you can call
setoutputmarkupid(some unique string)

-igor

On Tue, Mar 17, 2009 at 2:40 PM, Guido Helmers <gu...@gmail.com> wrote:
> Hi,
>
> (Wicket 1.3.5 / Java 1.6)
>
> I have a page with a DefaultDataTable containing an AjaxFallbackLink in one
> of its columns. When the page is rendered for the first time, the link in
> row 1 has component id path "table:rows:1:cells:3:cell". When I click this
> link while Ajax is disabled, the page is refreshed, and now the link in row
> 1 (which is still displaying exactly the same item) has changed to
> "table:rows:3:cells:3:cell" (my table has 2 rows, hence the row id increase
> from 1 to 3). A sample page and unit test can be found at the bottom of this
> email (I provided a complete package, including WebApplication and markup
> page).
>
> In my data table tests I would like to refer to data table rows and cells by
> their component id paths (see DataTablePageTest.java). Currently my tests
> are not very robust, because the component id paths of the DataTable rows
> and cells vary over time and depend on the page size and number of items
> displayed (if page size = 2, after a click, row id 1 has suddenly become 1 +
> 2 = 3).
>
> The reason that in case of no ajax the row ids increase, is that on a page
> refresh the DataGridView.onPopulate() is called, and if you look in
> RefreshingView.onPopulate() -> newItemFactory() you will see that a new
> child id is retrieved for every item. Because childIdCounter is a private
> field of RepeatingView, and the counter is never reset to 0, my row #1 has
> suddenly become row #3.
>
> So I'm wondering:
> * Is there trick to reset the counter on a page refresh and what side
> effects will it have? (RepeatingView.childIdCounter is private and there are
> no public/protected methods to influence the counter so I have no idea how
> to do it).
> * Does anyone have suggestions to improve the below code / unit test, so
> that table rows and table cells can be referenced (in the unit test) by a
> constant identifier that does not depend on the page size and that doesn't
> change over time?
>
> Cheers,
> Guido
>
>
> *_______________
> MyWebApplication.java
> *
> package wicket;
>
> import org.apache.wicket.protocol.http.WebApplication;
>
> public class MyWebApplication extends WebApplication {
>
>    @Override
>    public Class getHomePage() {
>        return DataTablePage.class;
>    }
> }
>
>
>
> *_______________
> MyItem.java
> *
> package wicket;
>
> import java.io.Serializable;
>
> public class MyItem implements Serializable {
>
>    private static final long serialVersionUID = 1L;
>
>    private String code;
>
>    private String description;
>
>    public MyItem(String code, String description) {
>        this.code = code;
>        this.description = description;
>    }
>
>    public String getCode() {
>        return code;
>    }
>
>    public String getDescription() {
>        return description;
>    }
> }
>
>
>
> *_______________
> MyDataProvider.java
> *
> package wicket;
>
> import java.util.ArrayList;
> import java.util.Iterator;
> import java.util.List;
>
> import nl.rotterdam.ioo.pzr.midoffice.domain.search.SortParams;
>
> import
> org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
> import org.apache.wicket.model.IModel;
> import org.apache.wicket.model.Model;
>
> public class MyDataProvider extends SortableDataProvider {
>
>    private static final long serialVersionUID = 1L;
>
>    private static List<MyItem> items = new ArrayList<MyItem>();
>    static {
>        items.add(new MyItem("CODE1", "description1"));
>        items.add(new MyItem("CODE2", "description2"));
>    }
>
>    protected SortParams sortParams;
>
>    public void setQueryParam(SortParams sortParams) {
>        this.sortParams = sortParams;
>    }
>
>    public MyDataProvider() {
>    }
>
>    public Iterator<?> iterator(int first, int count) {
>        return items.iterator();
>    }
>
>    public IModel model(Object object) {
>        return new Model((MyItem) object);
>    }
>
>    public int size() {
>        return items.size();
>    }
> }
>
>
> *_______________
> DataTablePage.java
> *
> package wicket;
>
> import java.util.Arrays;
>
> import org.apache.wicket.ajax.AjaxRequestTarget;
> import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
> import
> org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
> import
> org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
> import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
> import
> org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
> import org.apache.wicket.markup.html.WebPage;
> import org.apache.wicket.markup.repeater.Item;
> import org.apache.wicket.model.IModel;
> import org.apache.wicket.model.Model;
>
> public class DataTablePage extends WebPage {
>
>    private final DefaultDataTable table;
>
>    public DataTablePage() {
>
>        MyDataProvider dataProvider = new MyDataProvider();
>        IColumn[] columns = new IColumn[3];
>
>        columns[0] = new PropertyColumn(new Model("Code"), "code", "code");
>        columns[1] = new PropertyColumn(new Model("Description"),
> "description");
>        columns[2] = new AbstractColumn(new Model("Select")) {
>            private static final long serialVersionUID = 1L;
>
>            public void populateItem(Item cellItem, String componentId,
> IModel rowModel) {
>                final MyItem item = (MyItem) rowModel.getObject();
>                AjaxFallbackLink link = new AjaxFallbackLink(componentId) {
>                    @Override
>                    public void onClick(AjaxRequestTarget target) {
>                        System.out.println("Click item " + item.getCode() +
> " with target=" + target);
>                    }
>                };
>                cellItem.add(link);
>            }
>        };
>
>        table = new DefaultDataTable("table", Arrays.asList(columns),
> dataProvider, 10);
>        add(table);
>    }
> }
>
>
> *_______________
> DataTablePage.html
> *
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
> http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="
> http://wicket.apache.org/" xml:lang="nl" lang="nl">
> <head>
>    <title>DataTable test page</title>
> </head>
> <body>
>    <table wicket:id="table"></table>
> </body>
> </html>
>
>
> *_______________
> DataTablePageTest.java
> *
> package wicket;
>
> import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
> import org.apache.wicket.util.tester.WicketTester;
> import org.junit.After;
> import org.junit.Before;
> import org.junit.Test;
>
> public class DataTablePageTest {
>
>    private WicketTester tester;
>
>    @Before
>    public void setUp() throws Exception {
>        MyWebApplication application = new MyWebApplication();
>        tester = new WicketTester(application);
>    }
>
>    @After
>    public void tearDown() throws Exception {
>        tester.destroy();
>    }
>
>    @Test
>    public void testWithAjax() {
>        test(true);
>    }
>
>    @Test
>    public void testWithoutAjax() {
>        test(false);
>    }
>
>    private void test(boolean ajax) {
>        String pathToLinkInRow1 = "table:rows:1:cells:3:cell";
>
>        tester.startPage(DataTablePage.class);
>        tester.assertRenderedPage(DataTablePage.class);
>
>        //tester.debugComponentTrees();
>        tester.clickLink(pathToLinkInRow1, ajax);
>        //tester.debugComponentTrees();
>
>        // the following assertion fails if ajax=false
>        tester.assertComponent(pathToLinkInRow1, AjaxFallbackLink.class);
>    }
> }
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@wicket.apache.org
For additional commands, e-mail: users-help@wicket.apache.org


Re: DataTable testability - RepeatingView.childIdCounter not reset after a page refresh

Posted by helmers <gu...@GMAIL.COM>.
I solved it as follows:

dataTable.setItemReuseStrategy(new ReuseIfModelsEqualStrategy());

This will prevent the table from creating new items over and over again,
even if they represent the same object. See the javadoc for
ReuseIfModelsEqualStrategy.



helmers wrote:
> 
> I have a page with a DefaultDataTable containing an AjaxFallbackLink in
> one
> of its columns. When the page is rendered for the first time, the link in
> row 1 has component id path "table:rows:1:cells:3:cell". When I click this
> link while Ajax is disabled, the page is refreshed, and now the link in
> row
> 1 (which is still displaying exactly the same item) has changed to
> "table:rows:3:cells:3:cell" (my table has 2 rows, hence the row id
> increase
> from 1 to 3).
> 
> In my data table tests I would like to refer to data table rows and cells
> by
> their component id paths (see DataTablePageTest.java). Currently my tests
> are not very robust, because the component id paths of the DataTable rows
> and cells vary over time and depend on the page size and number of items
> displayed (if page size = 2, after a click, row id 1 has suddenly become 1
> +
> 2 = 3).
> 
> The reason that in case of no ajax the row ids increase, is that on a page
> refresh the DataGridView.onPopulate() is called, and if you look in
> RefreshingView.onPopulate() -> newItemFactory() you will see that a new
> child id is retrieved for every item. Because childIdCounter is a private
> field of RepeatingView, and the counter is never reset to 0, my row #1 has
> suddenly become row #3.
> 

-- 
View this message in context: http://www.nabble.com/DataTable-testability---RepeatingView.childIdCounter-not-reset-after--a-page-refresh-tp22568486p22626268.html
Sent from the Wicket - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@wicket.apache.org
For additional commands, e-mail: users-help@wicket.apache.org