+ ]]>
+
+
+ `;
+
static VIEWSTATE_1 = `
diff --git a/api/src/client/typescript/faces/test/xhrCore/ResponseTest.spec.ts b/api/src/client/typescript/faces/test/xhrCore/ResponseTest.spec.ts
index 726c6ee6bb..fe75022c18 100644
--- a/api/src/client/typescript/faces/test/xhrCore/ResponseTest.spec.ts
+++ b/api/src/client/typescript/faces/test/xhrCore/ResponseTest.spec.ts
@@ -229,6 +229,88 @@ describe('Tests of the various aspects of the response protocol functionality',
});
+ it("must handle table cell, row insert/delete and header/footer replacement", function () {
+ window.document.body.innerHTML = `
+`;
+
+ expect(DQ.byId("row_0").isPresent(), "sanity check, 10 rows present before the update").to.be.true;
+ expect(DQ.byId("row_9").isPresent(), "sanity check, 10 rows present before the update").to.be.true;
+
+ faces.ajax.request(window.document.getElementById("cmd_table_update"), null, {
+ execute: "cmd_table_update",
+ render: "dataTable"
+ });
+
+ this.respond(XmlResponses.TABLE_ROW_CELL_HEADER_FOOTER_UPDATE);
+
+ // cell replacement, only the targeted cell changed, the row and the sibling cell survived
+ expect(DQ.byId("cell_5").innerHTML).to.eq("name5-updated");
+ expect(DQ.byId("row_5").isPresent()).to.be.true;
+ expect(DQ.byId("cell_5b").innerHTML).to.eq("value5");
+
+ // row delete
+ expect(DQ.byId("row_9").isAbsent()).to.be.true;
+
+ // untouched rows must still be present and unchanged
+ expect(DQ.byId("row_0").isPresent()).to.be.true;
+ expect(DQ.byId("cell_0").innerHTML).to.eq("name0");
+
+ // row insert before an existing row, order must be preserved
+ expect(DQ.byId("row_inserted_before").isPresent()).to.be.true;
+ expect(DQ.byId("row_2").isPresent()).to.be.true;
+ let bodyHtml = DQ.byId(document.body).html().value as string;
+ let posInsertedBefore = bodyHtml.indexOf("insertedBeforeRow2");
+ let posRow1 = bodyHtml.indexOf("id=\"row_1\"");
+ let posRow2 = bodyHtml.indexOf("id=\"row_2\"");
+ expect(posRow1 < posInsertedBefore && posInsertedBefore < posRow2).to.be.true;
+
+ // row insert after an existing row, order must be preserved
+ expect(DQ.byId("row_inserted_after").isPresent()).to.be.true;
+ let posInsertedAfter = bodyHtml.indexOf("insertedAfterRow7");
+ let posRow7 = bodyHtml.indexOf("id=\"row_7\"");
+ let posRow8 = bodyHtml.indexOf("id=\"row_8\"");
+ expect(posRow7 < posInsertedAfter && posInsertedAfter < posRow8).to.be.true;
+
+ // header (thead) replacement
+ expect(DQ.byId("header_cell").innerHTML).to.eq("NameUpdated");
+ expect(DQ.byId("header_cell2").innerHTML).to.eq("ValueUpdated");
+
+ // footer (tfoot) replacement
+ expect(DQ.byId("footer_cell").innerHTML).to.eq("FooterUpdated");
+
+ // the table element itself must not have been replaced wholesale, still exists exactly once
+ expect(DQ.querySelectorAll("#dataTable").length).to.eq(1);
+ });
+
it("must have processed a proper eval of a script given in the eval tag", function () {
DQ.byId("cmd_eval").click();
this.respond(XmlResponses.EVAL_1);
@@ -238,6 +320,44 @@ describe('Tests of the various aspects of the response protocol functionality',
});
+ it("must forward an explicit nonce attribute on the eval node to the generated script element", function () {
+ const createElementSpy = sinon.spy(document, "createElement");
+
+ DQ.byId("cmd_eval").click();
+ this.respond(XmlResponses.EVAL_WITH_EXPLICIT_NONCE);
+
+ const evalScript: any = createElementSpy.returnValues.find((el: any) =>
+ el?.tagName === "SCRIPT" && (el.innerHTML ?? "").indexOf("eval test succeeded") != -1);
+
+ expect(evalScript, "the eval code must have run through a generated script element").to.exist;
+ expect(evalScript.nonce).to.eq("serverSuppliedNonce");
+
+ createElementSpy.restore();
+ });
+
+ it("must fall back to the page's own CSP nonce when the eval node carries none", function () {
+ // window.myfaces is a shared module-level singleton, not per-jsdom-window state,
+ // so this mutation must be restored or it leaks into unrelated tests later in the run
+ const originalConfig = window.myfaces.config;
+ window.myfaces.config = {...window.myfaces.config, cspMeta: {nonce: "fallbackNonce"}};
+
+ const createElementSpy = sinon.spy(document, "createElement");
+
+ try {
+ DQ.byId("cmd_eval").click();
+ this.respond(XmlResponses.EVAL_1);
+
+ const evalScript: any = createElementSpy.returnValues.find((el: any) =>
+ el?.tagName === "SCRIPT" && (el.innerHTML ?? "").indexOf("eval test succeeded") != -1);
+
+ expect(evalScript, "the eval code must have run through a generated script element").to.exist;
+ expect(evalScript.nonce).to.eq("fallbackNonce");
+ } finally {
+ createElementSpy.restore();
+ window.myfaces.config = originalConfig;
+ }
+ });
+
it("must have updated the viewstates properly", function (done) {
DQ.byId("cmd_eval").click();
/*js full submit form, coming from the integration tests*/
diff --git a/api/src/client/typescript/mona_dish/DomQuery.ts b/api/src/client/typescript/mona_dish/DomQuery.ts
index 7d6614b6c8..777ebe630b 100644
--- a/api/src/client/typescript/mona_dish/DomQuery.ts
+++ b/api/src/client/typescript/mona_dish/DomQuery.ts
@@ -472,9 +472,9 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
if (queryRes.length) {
found.push(queryRes);
}
- let shadowRoots = this.querySelectorAll("*").shadowRoot;
+ let shadowRoots = this._collectShadowRoots();
if (shadowRoots.length) {
- let shadowRes = shadowRoots.querySelectorAllDeep(queryStr);
+ let shadowRes = new DomQuery(shadowRoots).querySelectorAllDeep(queryStr);
if (shadowRes.length) {
found.push(shadowRes);
}
@@ -482,6 +482,37 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
return new DomQuery(found);
}
+ /**
+ * Collects the shadow roots hosted by the light-DOM descendants of each root
+ * node in a single pass.
+ *
+ * This replaces the prior `querySelectorAll("*").shadowRoot`, which
+ * materialized a DomQuery wrapping every element on the page and then walked
+ * that throwaway collection a second time through the shadowRoot getter. We
+ * still have to inspect every element - there is no CSS selector for "has a
+ * shadow root", so the cost stays O(number of elements) - but we drop the
+ * intermediate all-elements DomQuery and the redundant second traversal.
+ *
+ * @private
+ */
+ private _collectShadowRoots(): ShadowRoot[] {
+ let shadowRoots: ShadowRoot[] = [];
+ for (let cnt = 0; cnt < (this?.rootNode?.length ?? 0); cnt++) {
+ let root: any = this.rootNode[cnt];
+ if (!root?.querySelectorAll) {
+ continue;
+ }
+ let all = root.querySelectorAll("*");
+ for (let i = 0, len = all.length; i < len; i++) {
+ let shadowRoot = (all[i] as Element).shadowRoot;
+ if (shadowRoot) {
+ shadowRoots.push(shadowRoot);
+ }
+ }
+ }
+ return shadowRoots;
+ }
+
/**
* disabled flag
@@ -507,7 +538,11 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
get childNodes(): DomQuery {
let childNodeArr: Array = [];
this.eachElem((item: Element) => {
- childNodeArr = childNodeArr.concat(objToArray(item.childNodes));
+ // push the live childNodes list straight into the single target in
+ // chunks instead of concat(objToArray(...)) per root, which both
+ // copied each child list and reallocated the growing accumulator
+ // (O(roots * total children))
+ pushChunked(childNodeArr, item.childNodes as ArrayLike);
});
return new DomQuery(childNodeArr);
}
@@ -793,6 +828,11 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
);
}
+ // a "deep" id search must collect matches across every scope: ids are
+ // unique only within a single node-tree, so the same id may legitimately
+ // exist in the light DOM and inside one or more shadow roots at once.
+ // We therefore cannot short-circuit on a light-DOM hit and must run the
+ // full deep search.
let subItems = this.querySelectorAllDeep(`[id="${id}"]`);
if (subItems.length) {
res.push(subItems);
@@ -810,9 +850,12 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
byTagName(tagName: string, includeRoot ?: boolean, deep ?: boolean): DomQuery {
let res: Array = [];
if (includeRoot) {
- res = Es2019ArrayFrom(this?.rootNode ?? [])
- .filter(element => element?.tagName == tagName)
- .reduce((reduction: any, item: Element) => reduction.concat([item]), res);
+ // append the matching roots in a single pass; the prior
+ // reduce(reduction.concat([item])) reallocated the accumulator on
+ // every match (O(matches^2))
+ let matchingRoots = Es2019ArrayFrom(this?.rootNode ?? [])
+ .filter(element => element?.tagName == tagName);
+ pushChunked(res, matchingRoots);
}
(deep) ? res.push(this.querySelectorAllDeep(tagName)) : res.push(this.querySelectorAll(tagName));
@@ -1449,7 +1492,7 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
&& null != src
&& src.length > 0
) {
- let nonce = item?.nonce ?? (item.getAttribute('nonce') as any).value;
+ let nonce = item?.nonce || item.getAttribute('nonce');
// we have to move this into an inner if because chrome otherwise chokes
// due to changing the and order instead of relying on left to right
// if jsf.js is already registered we do not replace it anymore
@@ -1488,7 +1531,7 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
go = true;
}
}
- let nonce = item?.nonce ?? (item.getAttribute('nonce') as any).value ?? '';
+ let nonce = item?.nonce || item.getAttribute('nonce') || '';
// we have to run the script under a global context
// we store the script for fewer calls to eval
finalScripts.push({
@@ -2023,7 +2066,11 @@ export class DomQuery implements IDomQuery, IStreamDataSource, Iterabl
continue;
}
let res = this.rootNode[cnt].querySelectorAll(selector);
- nodes = nodes.concat(objToArray(res));
+ // push the NodeList straight into the single target array in
+ // argument-stack-safe chunks; this avoids the objToArray copy plus
+ // the concat reallocation, which doubled a large result set (e.g. the
+ // querySelectorAll("*") shadow scan) on every root iteration
+ pushChunked(nodes, res as ArrayLike);
}
return new DomQuery(nodes);
diff --git a/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/ResponseMockup.java b/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/ResponseMockup.java
index 8ea77bf903..08bb34697b 100644
--- a/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/ResponseMockup.java
+++ b/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/ResponseMockup.java
@@ -28,7 +28,6 @@
import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.Insert2;
import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.PartialResponse;
import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.Update;
-import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.responses.TableResponseMockups;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
@@ -198,44 +197,6 @@ else if (op.trim().toLowerCase().equals(ILLEGAL_RESPONSE_2))
{
illegalResponse2(out);
}
- else if (op.trim().equalsIgnoreCase(TABLE_REPLACE_HEAD))
- {
- TableResponseMockups.tableReplaceHead(viewData, out, root);
-
- }
- else if (op.trim().equalsIgnoreCase(TABLE_REPLACE_BODY))
- {
- TableResponseMockups.tableReplaceBody(viewData, out, root);
- }
- else if (op.trim().equalsIgnoreCase(TABLE_INSERT_ROW_HEAD))
- {
- TableResponseMockups.tableInsertRowHead(viewData, out, root);
- }
- else if (op.trim().equalsIgnoreCase(TABLE_INSERT_ROW_BODY))
- {
- TableResponseMockups.tableInsertRowBody(viewData, out, root);
- }
- else if (op.trim().equalsIgnoreCase(TABLE_INSERT_COLUMN_HEAD))
- {
- TableResponseMockups.tableInsetColumnHead(viewData, out, root);
- }
- else if (op.trim().equalsIgnoreCase(TABLE_INSERT_COLUMN_BODY))
- {
- TableResponseMockups.tableInsertColumnBody(viewData, out, root);
- }
- else if (op.trim().equalsIgnoreCase(TABLE_INSERT_FOOTER))
- {
- TableResponseMockups.tableInsertFooter(out, root);
- }
- else if (op.trim().equalsIgnoreCase(TABLE_INSERT_BODY))
- {
- TableResponseMockups.tableInsertBody(out, root);
- }
- else if (op.trim().equalsIgnoreCase(EXECUTE_NONE))
- {
- TableResponseMockups.execteNone(request, out, root);
- }
-
}
finally
{
diff --git a/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/responses/TableResponseMockups.java b/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/responses/TableResponseMockups.java
deleted file mode 100644
index f2389dbf71..0000000000
--- a/integration-tests/ajax/src/main/java/org/apache/myfaces/core/integrationtests/ajax/test1Protocol/responses/TableResponseMockups.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.myfaces.core.integrationtests.ajax.test1Protocol.responses;
-
-import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.ViewData;
-import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.Changes;
-import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.Insert2;
-import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.PartialResponse;
-import org.apache.myfaces.core.integrationtests.ajax.test1Protocol.jsfxmlnodes.Update;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.io.PrintWriter;
-
-/**
- * A helper class to encapsule the table responses
- */
-public class TableResponseMockups
-{
-
-
- public static void execteNone(HttpServletRequest request, PrintWriter out, PartialResponse root)
- {
- boolean execute = request.getParameter("jakarta.faces.partial.execute") != null;
- boolean render = request.getParameter("jakarta.faces.partial.render") != null;
-
- Changes changes = new Changes(root);
- changes.addChild(new Update(changes, "result", (!execute && !render) ? "
Table tests for the basic protocol operations. Due to the different
- handling of table elements in the dom operations (especially in legacy browsers), t
- his separate test is was written. It probably will be obsolete with JSF 3.0 because
- most of the legacy support except for IE11 will be cut off by then.
-
-
-
-
-
-
-
-
-
-
-
column1 in line1
-
colum2 in line2
-
-
-
-
-
column1 in line1 body
-
column2 in line1
- body
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/integration-tests/ajax/src/main/webapp/test5-viewbody-full-response.xhtml b/integration-tests/ajax/src/main/webapp/test4-viewbody-full-response.xhtml
similarity index 100%
rename from integration-tests/ajax/src/main/webapp/test5-viewbody-full-response.xhtml
rename to integration-tests/ajax/src/main/webapp/test4-viewbody-full-response.xhtml
diff --git a/integration-tests/ajax/src/test/java/org/apache/myfaces/core/integrationtests/ajax/IntegrationTest.java b/integration-tests/ajax/src/test/java/org/apache/myfaces/core/integrationtests/ajax/IntegrationTest.java
index 6ef5d25866..2c97e41911 100644
--- a/integration-tests/ajax/src/test/java/org/apache/myfaces/core/integrationtests/ajax/IntegrationTest.java
+++ b/integration-tests/ajax/src/test/java/org/apache/myfaces/core/integrationtests/ajax/IntegrationTest.java
@@ -211,107 +211,10 @@ public void testChain()
assertFalse(testSource.contains("test4 failed"));
}
-
- @Test
- public void testBasicTable()
- {
- webDriver.get(contextPath + "test4-tablebasic.jsf");
- resetServerValues();
-
- trigger("replace_head", webDriver ->
- {
- final WebElement testTable = webDriver.findElement(new By.ById("testTable"));
-
- return testTable.getText().contains("column1 in line1 replaced") &&
- testTable.getText().contains("script evaled0");
- });
-
- trigger("replace_body", webDriver ->
- {
- final WebElement tableSegment = webDriver.findElement(new By.ById("body_row1_col1"));
- return tableSegment.getText().contains("column1 in line1 replaced") &&
- tableSegment.getText().contains("script evaled");
- });
-
- trigger("insert_row_head", webDriver ->
- {
- final WebElement headRow0 = webDriver.findElement(new By.ById("head_row1_0"));
- final WebElement headRow1 = webDriver.findElement(new By.ById("head_row1"));
-
- return headRow1.getLocation().y > headRow0.getLocation().y &&
- headRow0.getText().contains("column1 in line1 inserted before") &&
- headRow0.getText().contains("colum2 in line2 inserted before");
- });
-
-
- trigger("insert_row_body", webDriver ->
- {
- final WebElement bodyRowCol1 = webDriver.findElement(new By.ById("body_row1_col1"));
- final WebElement bodyRowCol2 = webDriver.findElement(new By.ById("body_row1_col2"));
- final WebElement bodyRowCol0 = webDriver.findElement(new By.ById("body_row1_3_col1"));
- final WebElement bodyRowCol4 = webDriver.findElement(new By.ById("body_row1_4_col1"));
-
- return bodyRowCol0.getLocation().y < bodyRowCol1.getLocation().y &&
- bodyRowCol1.getLocation().y < bodyRowCol4.getLocation().y &&
-
- bodyRowCol1.getText().contains("column1 in line1 inserted after") &&
- bodyRowCol1.getText().contains("evaled") &&
- bodyRowCol2.getText().contains("colum2 in line1 replaced");
- });
-
- trigger("insert_column_head", webDriver ->
- {
- final WebElement headCol0 = webDriver.findElement(new By.ById("head_col1_1_4"));
- final WebElement headCol1 = webDriver.findElement(new By.ById("head_col1_1_5"));
- final WebElement headCol2 = webDriver.findElement(new By.ById("head_col1"));
- final WebElement headCol3 = webDriver.findElement(new By.ById("head_col2"));
- final WebElement headCol4 = webDriver.findElement(new By.ById("head_col1_1_6"));
- final WebElement headCol5 = webDriver.findElement(new By.ById("head_col1_1_7"));
-
- return headCol0.getLocation().x < headCol1.getLocation().x &&
- headCol1.getLocation().x < headCol2.getLocation().x &&
- headCol3.getLocation().x < headCol4.getLocation().x &&
- headCol4.getLocation().x < headCol5.getLocation().x &&
- headCol1.getLocation().y == headCol2.getLocation().y &&
- headCol2.getLocation().y == headCol3.getLocation().y &&
- headCol3.getLocation().y == headCol4.getLocation().y &&
- headCol4.getLocation().y == headCol5.getLocation().y;
-
- });
-
-
- trigger("insert_column_body", webDriver ->
- {
- final WebElement bodyCol0 = webDriver.findElement(new By.ById("body_row1_col1_1_8"));
- final WebElement bodyCol1 = webDriver.findElement(new By.ById("body_row1_col1_1_9"));
- final WebElement bodyCol2 = webDriver.findElement(new By.ById("body_row1_col1"));
- final WebElement bodyCol3 = webDriver.findElement(new By.ById("body_row1_col2"));
- final WebElement bodyCol4 = webDriver.findElement(new By.ById("body_row1_col1_1_10"));
- final WebElement bodyCol5 = webDriver.findElement(new By.ById("body_row1_col1_1_11"));
-
- return bodyCol0.getLocation().x < bodyCol1.getLocation().x &&
- bodyCol1.getLocation().x < bodyCol2.getLocation().x &&
- bodyCol3.getLocation().x < bodyCol4.getLocation().x &&
- bodyCol4.getLocation().x < bodyCol5.getLocation().x &&
- bodyCol1.getLocation().y == bodyCol2.getLocation().y &&
- bodyCol2.getLocation().y == bodyCol3.getLocation().y &&
- bodyCol3.getLocation().y == bodyCol4.getLocation().y &&
- bodyCol4.getLocation().y == bodyCol5.getLocation().y;
-
- });
-
- trigger("insert_body", webDriver ->
- {
- return webDriver.getPageSource().contains("") &&
- webDriver.getPageSource().contains("second body added");
- });
-
- }
-
@Test
public void testViewRootBodyReplacement()
{
- webDriver.get(contextPath + "test5-viewbody-full-response.jsf");
+ webDriver.get(contextPath + "test4-viewbody-full-response.jsf");
resetServerValues();
trigger("cmd_body1", webDriver1 -> webDriver1.getPageSource().contains("Test for body change done") &&
webDriver1.getPageSource().contains("Body replacement test successful"));
diff --git a/integration-tests/exactMapping/src/test/java/org/apache/myfaces/core/integrationtests/IntegrationTest.java b/integration-tests/exactMapping/src/test/java/org/apache/myfaces/core/integrationtests/IntegrationTest.java
index 15dee1585a..08dbdc2284 100644
--- a/integration-tests/exactMapping/src/test/java/org/apache/myfaces/core/integrationtests/IntegrationTest.java
+++ b/integration-tests/exactMapping/src/test/java/org/apache/myfaces/core/integrationtests/IntegrationTest.java
@@ -114,6 +114,18 @@ public void testNonExactMapping()
Assert.assertTrue(webDriver.getPageSource().contains("foo-view"));
}
+ /**
+ * element.click() on a plain (non-AJAX) submit/link element returns as soon as the click event
+ * is dispatched, not once the resulting navigation/postback has actually completed - so a click
+ * can intermittently be followed by a findElement/getPageSource call that still sees the previous
+ * page. Waiting for a condition that only holds true on the new page (as testAjaxPostBack already
+ * does for its AJAX request) avoids that race.
+ */
+ private void waitUntil(ExpectedCondition condition)
+ {
+ new WebDriverWait(webDriver, Duration.ofSeconds(5)).until(condition);
+ }
+
@Test
public void testPostBack()
{
@@ -125,10 +137,11 @@ public void testPostBack()
// post to foo.xhtml
WebElement element = webDriver.findElement(By.id("form:commandButton"));
element.click();
+ waitUntil(driver -> driver.getPageSource().contains("foo invoked"));
// check if method was invoked
Assert.assertTrue(webDriver.getPageSource().contains("foo invoked"));
-
+
// check that the exact mapping is still used after post
Assert.assertTrue(webDriver.getCurrentUrl().equals(url));
}
@@ -144,6 +157,7 @@ public void testLinkToNonExactMapping()
// navigate to bar.xhtml
WebElement element = webDriver.findElement(By.id("form:button"));
element.click();
+ waitUntil(driver -> driver.getPageSource().contains("bar-view"));
// check if we are on bar.xhtml
Assert.assertTrue(webDriver.getPageSource().contains("bar-view"));
@@ -156,7 +170,7 @@ public void testLinkToNonExactMapping()
|| webDriver.getCurrentUrl().endsWith("/faces/bar")
|| webDriver.getCurrentUrl().endsWith("/faces/bar.xhtml"));
}
-
+
@Test
public void testPostBackOnNonExactMapping()
{
@@ -165,14 +179,16 @@ public void testPostBackOnNonExactMapping()
// nagivate to non-exact-mapping (bar.xhtml)
WebElement element = webDriver.findElement(By.id("form:button"));
element.click();
+ waitUntil(driver -> driver.getPageSource().contains("bar-view"));
// post to bar.xhtml
WebElement element1 = webDriver.findElement(By.id("form:commandButton"));
element1.click();
+ waitUntil(driver -> driver.getPageSource().contains("foo invoked"));
// check if post was successful
Assert.assertTrue(webDriver.getPageSource().contains("foo invoked"));
-
+
// check if we are on bar.xhtml
Assert.assertTrue(webDriver.getCurrentUrl().endsWith("/bar.jsf")
|| webDriver.getCurrentUrl().endsWith("/faces/bar")
diff --git a/integration-tests/faceletToXhtmlMapping/src/main/java/org/apache/myfaces/core/integrationtests/MarkerBean.java b/integration-tests/faceletToXhtmlMapping/src/main/java/org/apache/myfaces/core/integrationtests/MarkerBean.java
new file mode 100644
index 0000000000..c56deffb09
--- /dev/null
+++ b/integration-tests/faceletToXhtmlMapping/src/main/java/org/apache/myfaces/core/integrationtests/MarkerBean.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.core.integrationtests;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+/**
+ * Marker bean to enable the CDI context
+ */
+@ApplicationScoped
+public class MarkerBean
+{
+}
diff --git a/integration-tests/faceletToXhtmlMapping/src/test/resources/arquillian.xml b/integration-tests/faceletToXhtmlMapping/src/test/resources/arquillian.xml
index ff8d63b3ec..b94274b657 100644
--- a/integration-tests/faceletToXhtmlMapping/src/test/resources/arquillian.xml
+++ b/integration-tests/faceletToXhtmlMapping/src/test/resources/arquillian.xml
@@ -23,7 +23,6 @@
chromeHeadless
- 139.0
diff --git a/integration-tests/faceletToXhtmlMappingDisabled/src/main/java/org/apache/myfaces/core/integrationtests/MarkerBean.java b/integration-tests/faceletToXhtmlMappingDisabled/src/main/java/org/apache/myfaces/core/integrationtests/MarkerBean.java
new file mode 100644
index 0000000000..c56deffb09
--- /dev/null
+++ b/integration-tests/faceletToXhtmlMappingDisabled/src/main/java/org/apache/myfaces/core/integrationtests/MarkerBean.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.core.integrationtests;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+/**
+ * Marker bean to enable the CDI context
+ */
+@ApplicationScoped
+public class MarkerBean
+{
+}
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index ad82e7b1d7..b89bd15290 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -68,9 +68,6 @@
**/*IntegrationTest
-
- jdk-http-client
-
@@ -132,13 +129,7 @@
org.seleniumhq.seleniumselenium-java
- 4.7.2
- test
-
-
- org.seleniumhq.selenium
- selenium-http-jdk-client
- 4.7.2
+ 4.47.0test
@@ -272,6 +263,6 @@
UTF-81710.1.55
- 3.0.0-alpha.7
+ 3.0.1.Final