@@ -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