Skip to content

Commit b4e9b4c

Browse files
committed
textarea clone tests
1 parent 0b6c3e8 commit b4e9b4c

1 file changed

Lines changed: 199 additions & 0 deletions

File tree

src/test/java/org/htmlunit/javascript/host/html/HTMLTextAreaElementTest.java

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,205 @@ public void resetAfterTypingAndChildMutationWhileDirty_valueMatchesCurrentTextCo
14591459
assertEquals(getExpectedAlerts()[2], valueAfterReset);
14601460
}
14611461

1462+
/**
1463+
* After dirtying .value via real typing (so it has diverged from
1464+
* the child text content), a deep clone must preserve BOTH the dirtied value
1465+
* AND its decoupling from textContent -- not silently revert to the (cloned)
1466+
* children's content.
1467+
* @throws Exception if the test fails
1468+
*/
1469+
@Test
1470+
@Alerts({"seed-typed", "seed"})
1471+
public void cloneNodeAfterTyping_cloneRetainsDirtiedValue() throws Exception {
1472+
final String html = DOCTYPE_HTML
1473+
+ "<html>\n"
1474+
+ "<head></head>\n"
1475+
+ "<body>\n"
1476+
+ " <textarea id='foo'>seed</textarea>\n"
1477+
+ "</body>\n"
1478+
+ "</html>";
1479+
1480+
final WebDriver driver = loadPage2(html);
1481+
final WebElement textarea = driver.findElement(By.id("foo"));
1482+
textarea.click();
1483+
textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END));
1484+
textarea.sendKeys("-typed");
1485+
1486+
final JavascriptExecutor js = (JavascriptExecutor) driver;
1487+
final String cloneValue = (String) js.executeScript(
1488+
"return arguments[0].cloneNode(true).value;", textarea);
1489+
final String cloneTextContent = (String) js.executeScript(
1490+
"return arguments[0].cloneNode(true).textContent;", textarea);
1491+
1492+
assertEquals(getExpectedAlerts()[0], cloneValue);
1493+
assertEquals(getExpectedAlerts()[1], cloneTextContent);
1494+
}
1495+
1496+
/**
1497+
* A deep clone's children must be independent of the original's -- mutating
1498+
* the original's children AFTER cloning must not affect the clone's
1499+
* .textContent or (for a still-clean clone) its .value.
1500+
* @throws Exception if the test fails
1501+
*/
1502+
@Test
1503+
@Alerts({"changed", "seed"})
1504+
public void cloneNodeDeep_childrenAreIndependentOfOriginal() throws Exception {
1505+
final String html = DOCTYPE_HTML
1506+
+ "<html>\n"
1507+
+ "<head></head>\n"
1508+
+ "<body>\n"
1509+
+ " <textarea id='foo'>seed</textarea>\n"
1510+
+ "</body>\n"
1511+
+ "</html>";
1512+
1513+
final WebDriver driver = loadPage2(html);
1514+
final WebElement textarea = driver.findElement(By.id("foo"));
1515+
1516+
final JavascriptExecutor js = (JavascriptExecutor) driver;
1517+
js.executeScript(
1518+
"var c = arguments[0].cloneNode(true);"
1519+
+ "c.id = 'clone';"
1520+
+ "document.body.appendChild(c);",
1521+
textarea);
1522+
1523+
// mutate the ORIGINAL's children only, after cloning
1524+
js.executeScript(
1525+
"arguments[0].removeChild(arguments[0].firstChild);"
1526+
+ "arguments[0].appendChild(document.createTextNode('changed'));",
1527+
textarea);
1528+
1529+
final String originalValue = (String) js.executeScript("return arguments[0].value;", textarea);
1530+
final String cloneValue = (String) js.executeScript(
1531+
"return document.getElementById('clone').value;");
1532+
1533+
assertEquals(getExpectedAlerts()[0], originalValue);
1534+
assertEquals(getExpectedAlerts()[1], cloneValue);
1535+
}
1536+
1537+
/**
1538+
* A shallow clone (deep=false) doesn't copy children at all -- but since the
1539+
* dirtied value lives on the element itself, not in the DOM tree, a shallow
1540+
* clone of an already-dirtied textarea must still preserve the dirtied
1541+
* value, even though its childNodes/textContent end up empty.
1542+
* @throws Exception if the test fails
1543+
*/
1544+
@Test
1545+
@Alerts({"seed-typed", ""})
1546+
public void cloneNodeShallowAfterTyping_stillRetainsDirtiedValue() throws Exception {
1547+
final String html = DOCTYPE_HTML
1548+
+ "<html>\n"
1549+
+ "<head></head>\n"
1550+
+ "<body>\n"
1551+
+ " <textarea id='foo'>seed</textarea>\n"
1552+
+ "</body>\n"
1553+
+ "</html>";
1554+
1555+
final WebDriver driver = loadPage2(html);
1556+
final WebElement textarea = driver.findElement(By.id("foo"));
1557+
textarea.click();
1558+
textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END));
1559+
textarea.sendKeys("-typed");
1560+
1561+
final JavascriptExecutor js = (JavascriptExecutor) driver;
1562+
final String cloneValue = (String) js.executeScript(
1563+
"return arguments[0].cloneNode(false).value;", textarea);
1564+
final String cloneTextContent = (String) js.executeScript(
1565+
"return arguments[0].cloneNode(false).textContent;", textarea);
1566+
1567+
assertEquals(getExpectedAlerts()[0], cloneValue);
1568+
assertEquals(getExpectedAlerts()[1], cloneTextContent);
1569+
}
1570+
1571+
/**
1572+
* After cloning a still-CLEAN textarea and attaching the clone to the
1573+
* document, typing independently into the original and the clone (real
1574+
* keyboard input on each) must not cross-contaminate either one's value.
1575+
* @throws Exception if the test fails
1576+
*/
1577+
@Test
1578+
@Alerts({"original-text", "clone-text"})
1579+
public void cloneNodeThenIndependentTyping_noCrossContamination() throws Exception {
1580+
final String html = DOCTYPE_HTML
1581+
+ "<html>\n"
1582+
+ "<head></head>\n"
1583+
+ "<body>\n"
1584+
+ " <textarea id='foo'></textarea>\n"
1585+
+ " <script>\n"
1586+
+ " var c = document.getElementById('foo').cloneNode(true);\n"
1587+
+ " c.id = 'clone';\n"
1588+
+ " document.body.appendChild(c);\n"
1589+
+ " </script>\n"
1590+
+ "</body>\n"
1591+
+ "</html>";
1592+
1593+
final WebDriver driver = loadPage2(html);
1594+
final WebElement original = driver.findElement(By.id("foo"));
1595+
final WebElement clone = driver.findElement(By.id("clone"));
1596+
1597+
original.click();
1598+
original.sendKeys("original-text");
1599+
clone.click();
1600+
clone.sendKeys("clone-text");
1601+
1602+
final JavascriptExecutor js = (JavascriptExecutor) driver;
1603+
final String originalValue = (String) js.executeScript("return arguments[0].value;", original);
1604+
final String cloneValue = (String) js.executeScript("return arguments[0].value;", clone);
1605+
1606+
assertEquals(getExpectedAlerts()[0], originalValue);
1607+
assertEquals(getExpectedAlerts()[1], cloneValue);
1608+
}
1609+
1610+
/**
1611+
* Resetting a clone (via a real click on its OWN form's reset button) must
1612+
* only affect the clone -- the original, sitting in a separate form, must be
1613+
* untouched.
1614+
* @throws Exception if the test fails
1615+
*/
1616+
@Test
1617+
@Alerts({"seed-original-dirtied", "seed"})
1618+
public void cloneNodeThenResetOnCloneOnly_doesNotAffectOriginal() throws Exception {
1619+
final String html = DOCTYPE_HTML
1620+
+ "<html>\n"
1621+
+ "<head></head>\n"
1622+
+ "<body>\n"
1623+
+ " <form id='form1'>\n"
1624+
+ " <textarea id='foo'>seed</textarea>\n"
1625+
+ " <input id='resetBtn1' type='reset'>\n"
1626+
+ " </form>\n"
1627+
+ " <form id='form2'>\n"
1628+
+ " <input id='resetBtn2' type='reset'>\n"
1629+
+ " </form>\n"
1630+
+ " <script>\n"
1631+
+ " var c = document.getElementById('foo').cloneNode(true);\n"
1632+
+ " c.id = 'clone';\n"
1633+
+ " document.getElementById('form2').appendChild(c);\n"
1634+
+ " </script>\n"
1635+
+ "</body>\n"
1636+
+ "</html>";
1637+
1638+
final WebDriver driver = loadPage2(html);
1639+
final WebElement original = driver.findElement(By.id("foo"));
1640+
final WebElement clone = driver.findElement(By.id("clone"));
1641+
1642+
original.click();
1643+
original.sendKeys(Keys.chord(Keys.CONTROL, Keys.END));
1644+
original.sendKeys("-original-dirtied");
1645+
1646+
clone.click();
1647+
clone.sendKeys(Keys.chord(Keys.CONTROL, Keys.END));
1648+
clone.sendKeys("-clone-dirtied");
1649+
1650+
// reset only form2, which contains the clone
1651+
driver.findElement(By.id("resetBtn2")).click();
1652+
1653+
final JavascriptExecutor js = (JavascriptExecutor) driver;
1654+
final String originalValue = (String) js.executeScript("return arguments[0].value;", original);
1655+
final String cloneValue = (String) js.executeScript("return arguments[0].value;", clone);
1656+
1657+
assertEquals(getExpectedAlerts()[0], originalValue);
1658+
assertEquals(getExpectedAlerts()[1], cloneValue);
1659+
}
1660+
14621661
/**
14631662
* @throws Exception if test fails
14641663
*/

0 commit comments

Comments
 (0)