diff --git a/src/main/kotlin/kweb/ElementCreator.kt b/src/main/kotlin/kweb/ElementCreator.kt index 47076d309..38464c857 100755 --- a/src/main/kotlin/kweb/ElementCreator.kt +++ b/src/main/kotlin/kweb/ElementCreator.kt @@ -67,10 +67,6 @@ open class ElementCreator( val id: String = mutAttributes.computeIfAbsent("id") { JsonPrimitive("K" + browser.generateId()) }.content val htmlDoc = browser.htmlDocument.get() - val createElementStatement = when (namespace) { - null -> "document.createElement(tag);" - else -> "document.createElementNS(\"${namespace}\", tag);" - } when { htmlDoc != null -> { val parentElement = when (element) { @@ -92,6 +88,7 @@ open class ElementCreator( } element.browser.isCatchingOutbound() != null -> { + //language=JavaScript val createElementJs = """ let tag = {}; @@ -99,7 +96,8 @@ let attributes = {}; let myId = {}; let parentId = {}; let insertBefore = {}; -let newEl = $createElementStatement +let namespace = {}; +let newEl = namespace ? document.createElementNS(namespace, tag) : document.createElement(tag); newEl.setAttribute("id", myId); for (const key in attributes) { if ( key !== "id") { @@ -114,10 +112,11 @@ if (insertBefore !== undefined) { } else { parentElement.appendChild(newEl); } - """ +""" + browser.callJsFunction( - createElementJs, JsonPrimitive(tag), JsonObject(mutAttributes), id.json, - JsonPrimitive(element.id), JsonPrimitive(insertBefore ?: ""), JsonPrimitive(elementsCreatedCount) + createElementJs, JsonPrimitive(tag), JsonObject(mutAttributes), JsonPrimitive(id), + JsonPrimitive(element.id), JsonPrimitive(insertBefore ?: ""), JsonPrimitive(elementsCreatedCount), JsonPrimitive(namespace ?: "") ) } @@ -130,12 +129,13 @@ let attributes = {}; let myId = {}; let parentId = {}; let insertBefore = {}; -let newEl = document.createElement(tag); -if (attributes["id"] === undefined) { +let namespace = {}; +let newEl = namespace ? document.createElementNS(namespace, tag) : document.createElement(tag); +if (!attributes["id"]) { newEl.setAttribute("id", myId); } for (const key in attributes) { - newEl.setAttribute(key, attributes[key]); + newEl.setAttribute(key, attributes[key]); } let parentElement = document.getElementById(parentId); let startNode = document.getElementById(insertBefore) @@ -145,10 +145,10 @@ if (insertBefore !== undefined) { } else { parentElement.appendChild(newEl); } - """ +""" element.browser.callJsFunction( createElementJs, tag.json, JsonObject(mutAttributes), id.json, - element.id.json, JsonPrimitive(insertBefore ?: ""), JsonPrimitive(elementsCreatedCount) + element.id.json, JsonPrimitive(insertBefore ?: ""), JsonPrimitive(elementsCreatedCount), JsonPrimitive(namespace ?: "") ) } } diff --git a/src/main/kotlin/kweb/WebBrowser.kt b/src/main/kotlin/kweb/WebBrowser.kt index d8daf07e5..fb202239b 100755 --- a/src/main/kotlin/kweb/WebBrowser.kt +++ b/src/main/kotlin/kweb/WebBrowser.kt @@ -177,7 +177,7 @@ class WebBrowser(val sessionId: String, val httpRequestInfo: HttpRequestInfo, va if (outboundMessageCatcher == null) { kweb.callJs(sessionId, functionCall, debugInfo) } else { - logger.debug("Temporarily storing message for $sessionId in threadlocal outboundMessageCatcher") + logger.debug("Temporarily storing message for $sessionId in threadlocal outboundMessageCatcher type ${outboundMessageCatcher.catcherType}") outboundMessageCatcher.functionList.add(functionCall) //If we are collecting calls for an immediate event, we run the risk of the client calling JS code that has yet to be cached //A functionCall object having a non null js parameter, means the function has not been cached. @@ -220,7 +220,7 @@ class WebBrowser(val sessionId: String, val httpRequestInfo: HttpRequestInfo, va if (outboundMessageCatcher == null) { kweb.callJs(sessionId, functionCall, debugInfo) } else { - logger.debug("Temporarily storing message for $sessionId in threadlocal outboundMessageCatcher") + logger.debug("Temporarily storing message for $sessionId in threadlocal outboundMessageCatcher type ${outboundMessageCatcher.catcherType}") outboundMessageCatcher.functionList.add(functionCall) if (outboundMessageCatcher.catcherType == CatcherType.IMMEDIATE_EVENT) { if (functionCall.js != null) { diff --git a/src/test/kotlin/kweb/demos/todo/TodoDemoTest.kt b/src/test/kotlin/kweb/demos/todo/TodoDemoTest.kt index 9e9f8dc0b..375cdfaa3 100755 --- a/src/test/kotlin/kweb/demos/todo/TodoDemoTest.kt +++ b/src/test/kotlin/kweb/demos/todo/TodoDemoTest.kt @@ -2,6 +2,8 @@ package kweb.demos.todo import io.github.bonigarcia.seljup.Options import io.github.bonigarcia.seljup.SeleniumJupiter +import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.ints.shouldBeGreaterThan import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.ktor.util.* @@ -64,8 +66,10 @@ class TodoDemoTest { val todoItem = "Right eyelids closed, both feet behind" val site = TodoSite(driver) site.addTodoItem(todoItem) - await().pollInSameThread().untilAsserted { - site.driver.findElement(By.xpath("//${"div"}[text()='$todoItem']")).isDisplayed shouldBe true + await().untilAsserted { + val matchingCount = site.driver.findElements(By.xpath("//div[@class='content']")) + .count { it.text.contains(todoItem) } + matchingCount shouldBeExactly 1 } } @@ -84,9 +88,10 @@ class TodoDemoTest { site.addTodoItem(todoItem) //make sure it appears for second driver - await().pollInSameThread().untilAsserted { - site2.driver.findElement(By.xpath("//${"div"}[text()='$todoItem']")).isDisplayed shouldBe true - } + await().untilAsserted { + val matchingCount = site.driver.findElements(By.xpath("//div[@class='content']")) + .count { it.text.contains(todoItem) } + matchingCount shouldBeExactly 1 } } @Test