"window" 未在 java 中为 Selenium 定义 ScriptEngine

"window" is not defined ScriptEngine in java for Selenium

我在做什么

我试图在 java 脚本中调用一些在页面加载后执行的基本内容。我这样做是为了 Selenium。为什么?我听到你在问,这是因为我正在制作一个简单的等待工具,如果单击或以其他方式 'using' 网页元素导致页面重新加载,它会一直等到页面加载完毕。这个 'tool' 只是使用主线程之外的线程来尝试 web 元素,等待它的引用过时,并等待 'onload event' 出现在 java 脚本中。如果这两件事都发生在某个超时条件之前,那么我知道 A:网络元素导致页面重新加载,B:我已经适当地等待页面重新加载。这很有用,因为我可以通过编程确定给定的网络元素是否会导致页面重新加载,只需尝试它并自动等待它。

问题

为此,我需要在 java 中 运行 一个 java 脚本加载事件。我是 javascript 的新手,但我研究了 java 附带的 ScriptEngine API。我决定使用它并在 onload 事件发生时尝试 运行 一个简单的 java 脚本函数。问题是我不断收到 "window" is not defined 异常。由于我用于 运行 的 ScriptEngine 对象 java 脚本仅接受我正在 运行ning 的字符串,所以我无法很好地检查错误。

我试过的

我已经尝试研究有关此错误的文档并围绕堆栈溢出进行谷歌搜索,但我似乎找不到以 java 为中心的答案,也没有找到对我来说足够好的解释。我从研究中收集到的所有信息是,我可能需要将 URL 指定为 window 对象或其他内容,但其他来源让我相信如果我使用浏览器 window 应该已经定义了 window 对象。我不知道该相信什么。有问题的代码是:

WebDriverWait wait = new WebDriverWait(driver, timeoutSeconds);
//initialize a wait for a page to reload
try {
    //wait untill our element we clicked is stale
    wait.until(ExpectedConditions.stalenessOf(webElement));
    //try running javascript to do something (here i tried a popup)
    //later I want this code to wait until the page is loaded and
    //then send something BACK to the javacode that I can wait for
    //so that Basically I wait until the page onload event has fired
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine javascript = manager.getEngineByName("javascript");
    try {
        javascript.eval("window.addEventListener('load', function() 
                {" +
                " alert(ok); " +
                "})");
    } catch (ScriptException e) {
        e.printStackTrace();
        System.out.println("javascript thing failed");
    }

} catch (TimeoutException e) {
    //page remained static and webelement doesn't cause a page 
    //reload
}

请注意,此代码位于 运行 与 main 并排的线程中。简单的目的是等到我们点击的元素过时并且页面 onload 事件被触发。如果这两件事都没有发生,我们点击的网络元素就不会导致页面重新加载。如果元素变得陈旧,我们知道元素发生了变化,但页面不会重新加载。如果这两种情况都发生了,那么我们就知道网络元素会重新加载页面。一切都在适当地等待,下一个网络元素已准备好被发现。这对 Selenium 很有用,因为我不必担心页面重新加载或删除自身但不重新加载页面的元素或任何其他可能导致 StaleReference 异常在不应抛出时抛出的奇怪边缘情况。现在 运行 正在处理这个代码块 returns 这个堆栈跟踪:

Starting ChromeDriver 2.41.578737 (49da6702b16031c40d63e5618de03a32ff6c197e) on port 30355 Only local connections are allowed. Sep 17, 2018 3:59:11 PM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: OSS sendKeys[[ChromeDriver: chrome on XP (1c2e7600f13bc56ff3b60f9a2de6ee93)] -> name: q][Ljava.lang.CharSequence;@6dd2f3a9 page was static submit[[ChromeDriver: chrome on XP (1c2e7600f13bc56ff3b60f9a2de6ee93)] -> name: q]null

javascript thing failed

javax.script.ScriptException: ReferenceError: "window" is not defined in >at line number 1

page reloaded

at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:469) at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:453) at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:405) at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:401) at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:154) at java.scripting/javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264) at SeleniumTest.isPageReloaded.run(isPageReloaded.java:48) at java.base/java.lang.Thread.run(Thread.java:844) Caused by: :1 ReferenceError: "window" is not defined at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57) at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:319) at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:291) at jdk.scripting.nashorn/jdk.nashorn.internal.objects.Global.noSuchProperty(Global.java:1615) at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$\^eval_/1394969414.:program(:1) at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:655) at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513) at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:527) at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:448) ... 6 more

Process finished with exit code 0

补充说明

请注意堆栈跟踪中的粗线,这些是我添加的要在某些错误状态下打印的内容。 "page reloaded message" 在正常情况下也会打印为状态消息。它反映了代码的 if else 状态。 java脚本失败是为了捕获java脚本异常,更明显地看到它确实失败了。我只是想知道我应该做什么来定义 window 以便这个 java 脚本代码(和未来的 js 代码)对我来说 运行。考虑到我对 java 有经验,但对 java 脚本没有经验。

ScriptEngineManager 仅在 JVM 中执行 javascript,不在浏览器中执行。

但是'window'在浏览器中是全局变量,在JVM中不是。这就是为什么你得到 window is undefined.

您应该使用 executeScript() Selenium api 在浏览器中执行 javascript。

String script = "window.addEventListener('load', function() {" +
                "  alert('ok'); " +
                "})";

JavascriptExecutor js =(JavascriptExecutor)driver;
js.executeScript(script);