diff --git a/fitnesse/FitNesseRoot/ZkSuite/ProductionTest/content.txt b/fitnesse/FitNesseRoot/ZkSuite/ProductionTest/content.txt
new file mode 100644
index 0000000000..8acfa8a923
--- /dev/null
+++ b/fitnesse/FitNesseRoot/ZkSuite/ProductionTest/content.txt
@@ -0,0 +1,32 @@
+'''IDEMPIERE-520 Master/Detail bugs found using Production window'''
+
+!include -c ZkGardenAdminLogin
+
+!define windowId {$Production__Single_Product__1}
+
+|''open window''|!-Production (Single Product)-!|
+|''wait response''|
+|''window''|${windowId}|''click toolbar''|!-BtnNew-!|
+|''wait response''|
+|''element exists''|${windowId} $detailPane @tabbox|
+|''lookup''|${windowId} $Production $M_Product_ID|''search''|!-PatioSet-!|
+|''wait response''|
+|''with''|${windowId} $Production $ProductionQty @decimalbox|''set text''|!-1-!|
+|''window''|${windowId}|''click toolbar''|!-BtnSave-!|
+|''wait response''|
+|''window message''|${windowId}|is|!-Record saved-!|
+|''window''|${windowId}|''click detail toolbar''|!-BtnNew-!|
+|''wait response''|
+|''text of''|${windowId} $recordInfo|is|!-+*1/1-!|
+|''window''|${windowId}|''click toolbar''|!-BtnParentRecord-!|
+|''wait response''|
+|''window''|${windowId}|''click process button''|!-CreateFrom-!|
+|''wait response''|
+|''click''|${windowId} @window[title="Create Production"] $Ok|
+|''wait response''|
+|''window''|${windowId}|''click detail toolbar''|!-BtnEdit-!|
+|''wait response''|
+|''element visible''|${windowId} $detailPane @tab|
+|''window''|${windowId}|''next record''|
+|''wait response''|
+|''element invisible''|${windowId} $detailPane @tab|
diff --git a/fitnesse/FitNesseRoot/ZkSuite/ProductionTest/properties.xml b/fitnesse/FitNesseRoot/ZkSuite/ProductionTest/properties.xml
new file mode 100644
index 0000000000..3e87512357
--- /dev/null
+++ b/fitnesse/FitNesseRoot/ZkSuite/ProductionTest/properties.xml
@@ -0,0 +1,12 @@
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+ true
+ true
+
diff --git a/fitnesse/FitNesseRoot/ZkSuite/ProductionTestEmptyTable/content.txt b/fitnesse/FitNesseRoot/ZkSuite/ProductionTestEmptyTable/content.txt
new file mode 100644
index 0000000000..2ebfb7bcb0
--- /dev/null
+++ b/fitnesse/FitNesseRoot/ZkSuite/ProductionTestEmptyTable/content.txt
@@ -0,0 +1,31 @@
+'''IDEMPIERE-520 Master/Detail bugs found using Production window'''
+
+!include -c ZkGardenAdminLogin
+
+!define windowId {$Production__Single_Product__1}
+
+|''open window''|!-Production (Single Product)-!|
+|''wait response''|
+|''element exists''|${windowId} $detailPane @tabbox|
+|''lookup''|${windowId} $Production $M_Product_ID|''search''|!-PatioSet-!|
+|''wait response''|
+|''with''|${windowId} $Production $ProductionQty @decimalbox|''set text''|!-1-!|
+|''window''|${windowId}|''click toolbar''|!-BtnSave-!|
+|''wait response''|
+|''window message''|${windowId}|is|!-Record saved-!|
+|''window''|${windowId}|''click detail toolbar''|!-BtnNew-!|
+|''wait response''|
+|''text of''|${windowId} $recordInfo|is|!-+*1/1-!|
+|''window''|${windowId}|''click toolbar''|!-BtnParentRecord-!|
+|''wait response''|
+|''window''|${windowId}|''click process button''|!-CreateFrom-!|
+|''wait response''|
+|''click''|${windowId} @window[title="Create Production"] $Ok|
+|''wait response''|
+|''window''|${windowId}|''click detail toolbar''|!-BtnEdit-!|
+|''wait response''|
+|''element visible''|${windowId} $detailPane @tab|
+|''window''|${windowId}|''next record''|
+|''wait response''|
+|''element invisible''|${windowId} $detailPane @tab|
+
diff --git a/fitnesse/FitNesseRoot/ZkSuite/ProductionTestEmptyTable/properties.xml b/fitnesse/FitNesseRoot/ZkSuite/ProductionTestEmptyTable/properties.xml
new file mode 100644
index 0000000000..3e87512357
--- /dev/null
+++ b/fitnesse/FitNesseRoot/ZkSuite/ProductionTestEmptyTable/properties.xml
@@ -0,0 +1,12 @@
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+ true
+ true
+
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java
index 48ea779551..5f57941945 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADWindowContent.java
@@ -92,6 +92,7 @@ public class ADWindowContent extends AbstractADWindowContent
toolbar.setWindowNo(getWindowNo());
breadCrumb = new BreadCrumb(getWindowNo());
breadCrumb.setToolbarListener(this);
+ breadCrumb.setId("breadCrumb");
div.appendChild(breadCrumb);
//status bar
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java
index c3d383bd17..6dc1fafce8 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java
@@ -33,6 +33,7 @@ import java.util.TreeMap;
import java.util.logging.Level;
import org.adempiere.util.Callback;
+import org.adempiere.webui.AdempiereIdGenerator;
import org.adempiere.webui.AdempiereWebUI;
import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.WArchive;
@@ -232,6 +233,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
{
/** Initalise toolbar */
toolbar = new ADWindowToolbar(getWindowNo());
+ toolbar.setId("windowToolbar");
toolbar.addListener(this);
statusBar = new StatusBar();
@@ -2374,6 +2376,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
{
Clients.showBusy(getComponent(), " ");
final WCreateFromWindow window = (WCreateFromWindow) cf.getWindow();
+ window.setWidgetAttribute(AdempiereWebUI.WIDGET_INSTANCE_NAME, AdempiereIdGenerator.escapeId(window.getTitle()));
window.addEventListener(DialogEvents.ON_WINDOW_CLOSE, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java
index db84e85855..0c0539f127 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/BreadCrumb.java
@@ -132,6 +132,7 @@ public class BreadCrumb extends Div implements EventListener {
btnRecordInfo.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Who")));
btnRecordInfo.addEventListener(Events.ON_CLICK, this);
btnRecordInfo.setSclass("breadcrumb-record-info link");
+ btnRecordInfo.setId("recordInfo");
toolbar.appendChild(btnRecordInfo);
btnNext = createButton("Next", "Next", "Next");
toolbar.appendChild(btnNext);
diff --git a/org.idempiere.ui.zk.selenium/src/fitlibrary/zk/ZkFixture.java b/org.idempiere.ui.zk.selenium/src/fitlibrary/zk/ZkFixture.java
index 17f25b78d1..8a8d1bb139 100644
--- a/org.idempiere.ui.zk.selenium/src/fitlibrary/zk/ZkFixture.java
+++ b/org.idempiere.ui.zk.selenium/src/fitlibrary/zk/ZkFixture.java
@@ -98,6 +98,54 @@ public class ZkFixture extends SpiderFixture {
return (String) widget.eval(webDriver, "getSelectedTab().getLabel()");
}
+ //--- Search (lookup) --
+ @SimpleAction(wiki = "|''lookup''|xpath, id or other locator|''search''|value|", tooltip = "Search lookup with value.")
+ public void lookupSearch(String locator, String value) {
+ Widget widget = new Widget(locator + " @textbox");
+ WebElement element = widget.findElement(webDriver);
+ element.click();
+ widget.execute(webDriver, "setValue('"+value+"')");
+ widget.execute(webDriver, "fireOnChange()");
+ }
+
+ // ---- window ( tab ) ---
+ @SimpleAction(wiki = "|''open window''|menu label|", tooltip = "Open window with label.")
+ public void openWindow(String label) {
+ comboboxSelectItem("$treeSearchCombo", label);
+ }
+
+ @SimpleAction(wiki = "|''window''|xpath, id or other locator|''click process button''|button id|", tooltip = "Click a window's process button.")
+ public void windowClickProcessButton(String windowLocator, String btnId) {
+ click(windowLocator + " $windowToolbar $BtnProcess");
+ waitResponse();
+ click("@window[instanceName=\"processButtonPopup\"] $" + btnId);
+ }
+
+ @SimpleAction(wiki = "|''window''|xpath, id or other locator|''click toolbar''|value|", tooltip = "Click a window's toolbar button")
+ public void windowClickToolbar(String windowLocator, String toolbarButtonId) {
+ click(windowLocator + " $windowToolbar $" + toolbarButtonId);
+ }
+
+ @SimpleAction(wiki = "|''window''|xpath, id or other locator|''click detail toolbar''|value|", tooltip = "Click the detailpane's toolbar button")
+ public void windowClickDetailToolbar(String windowLocator, String toolbarButtonId) {
+ click(windowLocator + " $detailPane $" + toolbarButtonId + ":visible");
+ }
+
+ @SimpleAction(wiki = "|''window message''|xpath, id or other locator|", tooltip = "Current status message display for a window")
+ public String windowMessage(String windowLocator) {
+ return webDriver.findElement(Zk.jq(windowLocator +" $messages @label")).getText();
+ }
+
+ @SimpleAction(wiki = "|''window''|xpath, id or other locator|''next record''|value|", tooltip = "Navigate to next record.")
+ public void windowNextRecord(String windowLocator) {
+ click(windowLocator+" $breadCrumb $Next");
+ }
+
+ @SimpleAction(wiki = "|''window''|xpath, id or other locator|''previous record''|value|", tooltip = "Navigate to previous record.")
+ public void windowPreviousRecord(String windowLocator) {
+ click(windowLocator+" $breadCrumb $Previous");
+ }
+
// -------- Wait Ajax Response -----
@SimpleAction(wiki = "|''wait response''|", tooltip = "Wait for ajax response with default timeout value.")
public void waitResponse() {
diff --git a/org.idempiere.ui.zk.selenium/src/test/AbstractTestCase.java b/org.idempiere.ui.zk.selenium/src/test/AbstractTestCase.java
index e52f66023b..88537adca9 100644
--- a/org.idempiere.ui.zk.selenium/src/test/AbstractTestCase.java
+++ b/org.idempiere.ui.zk.selenium/src/test/AbstractTestCase.java
@@ -53,6 +53,14 @@ public class AbstractTestCase {
element.click();
}
+ protected void search(String locator, String label) {
+ Widget widget = new Widget(locator + " @textbox");
+ WebElement element = widget.findElement(driver);
+ element.click();
+ widget.execute(driver, "setValue('"+label+"')");
+ widget.execute(driver, "fireOnChange()");
+ }
+
protected void selectCheckbox(String locator, boolean select) {
final WebElement element = driver.findElement(Zk.jq("$"+locator+" ~ input"));
if (element.isSelected()) {
@@ -204,6 +212,36 @@ public class AbstractTestCase {
return false;
}
}
+
+ protected void openWindow(String label) {
+ comboboxSelectItem("$treeSearchCombo", label);
+ }
+
+ protected void clickProcessButton(String windowId, String btnId) {
+ clickButton("$"+windowId + " $windowToolbar $BtnProcess");
+ waitResponse();
+ clickButton("@window[instanceName=\"processButtonPopup\"] $" + btnId);
+ }
+
+ protected void clickToolbarButton(String windowId, String toolBarButtonId) {
+ clickButton("$" + windowId + " $windowToolbar $" + toolBarButtonId);
+ }
+
+ protected void clickDetailToolbarButton(String windowId, String toolBarButtonId) {
+ clickButton("$" + windowId + " $detailPane $" + toolBarButtonId + ":visible");
+ }
+
+ protected WebElement getWindowMessageLabel(String windowId) {
+ return driver.findElement(Zk.jq("$"+windowId +" $messages @label"));
+ }
+
+ protected void nextRecord(String windowId) {
+ clickButton("$"+windowId+" $breadCrumb $Next");
+ }
+
+ protected void previousRecord(String windowId) {
+ clickButton("$"+windowId+" $breadCrumb $Previous");
+ }
@After
public void tearDown() throws Exception {
diff --git a/org.idempiere.ui.zk.selenium/src/test/ProductionTest.java b/org.idempiere.ui.zk.selenium/src/test/ProductionTest.java
new file mode 100644
index 0000000000..9191f0f182
--- /dev/null
+++ b/org.idempiere.ui.zk.selenium/src/test/ProductionTest.java
@@ -0,0 +1,75 @@
+package test;
+
+import org.idempiere.ui.zk.selenium.Zk;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import org.openqa.selenium.WebElement;
+
+/**
+ * Test case for http://jira.idempiere.com/browse/IDEMPIERE-520
+ * @author hengsin
+ *
+ */
+public class ProductionTest extends AbstractTestCase {
+
+ @Test
+ public void testIDempiere520() throws Exception {
+ login();
+
+ String windowId = "Production__Single_Product__1";
+
+ openWindow("Production (Single Product)");
+
+ waitResponse();
+
+ //check detail is shown for new record
+ WebElement element = driver.findElement(Zk.jq("$"+windowId+" $detailPane @tabbox"));
+
+ assertTrue(element != null && element.isDisplayed());
+
+ search("$"+windowId+" $Production $M_Product_ID", "PatioSet");
+ waitResponse();
+
+ type("$"+windowId+" $Production $ProductionQty @decimalbox", "1");
+
+
+ clickToolbarButton(windowId, "BtnSave");
+ waitResponse();
+
+ //verify save successfull
+ element = getWindowMessageLabel(windowId);
+ assertTrue("Record saved".equals(element.getText()));
+
+ clickDetailToolbarButton(windowId, "BtnNew");
+
+ //verify +*1/1 for is shown for new record
+ waitResponse();
+ element = driver.findElement(Zk.jq("$"+windowId+" $recordInfo"));
+ assertEquals("+*1/1", element.getText());
+
+ //test for npe
+ clickToolbarButton(windowId, "BtnParentRecord");
+ waitResponse();
+
+ //create production lines
+ clickProcessButton(windowId, "CreateFrom");
+ waitResponse();
+ clickButton("$"+windowId+" @window[title=\"Create Production\"] $Ok");
+ waitResponse();
+
+ clickDetailToolbarButton(windowId, "BtnEdit");
+ waitResponse();
+
+ //verify qc tab visible for first record
+ element = driver.findElement(Zk.jq("$"+windowId+" $detailPane @tab"));
+ assertTrue(element != null && element.isDisplayed());
+
+ nextRecord(windowId);
+ waitResponse();
+
+ //verify qc tab is invisible for first record
+ element = driver.findElement(Zk.jq("$"+windowId+" $detailPane @tab"));
+ assertTrue(element == null || !element.isDisplayed());
+ }
+}
diff --git a/org.idempiere.ui.zk.selenium/src/test/SelectTabTest.java b/org.idempiere.ui.zk.selenium/src/test/SelectTabTest.java
index d580ca30bd..f5fe8b26d5 100644
--- a/org.idempiere.ui.zk.selenium/src/test/SelectTabTest.java
+++ b/org.idempiere.ui.zk.selenium/src/test/SelectTabTest.java
@@ -16,7 +16,7 @@ public class SelectTabTest extends AbstractTestCase {
public void testSelectTab() throws Exception {
login();
waitResponse();
- comboboxSelectItem("$treeSearchCombo", "Product");
+ openWindow("Product");
waitResponse();
clickButton("$findWindow_1 $simpleSearch $btnOk");
waitResponse();