java - 如何使用applescript从chromedriver实例关闭上传对话框窗口?
问题描述
我有一个硒测试(准确地说是硒),该场景需要上传文件。我要上传文件的元素是一个隐藏的输入字段,它位于 DOM 的末尾;
<input type="file" style="height: 0; width: 0; visibility: hidden;" tabindex="-1" accept="*">
并且仅在单击文件应该被“拖放”或从系统加载的区域后出现;
<a class="browse" ref="fileBrowse" href="#">select files...</a>
这意味着我无法使用迄今为止我知道的任何方法,而无需先单击该元素 - 例如,sendKeys、uploadFile、uploadFromClassPath 等。但是,当我单击该元素时,会出现一个对话框窗口。加载文件后,窗口不会关闭,我还没有找到一个可靠的解决方案来关闭该窗口。
我正在使用 macOS 和 chrome,这意味着我无法使用“autoIT”,也无法运行“sikuliX”来创建简单的屏幕截图脚本。
但是,如果我们忽略了 Web 驱动程序的实例存在,我可以使用 Automator 打乱一个 AppleScript,它工作得很好。意义; 如果我从控制台运行脚本,将网站设置为与自动化测试完全一致 - 它可以工作......不幸的是,一旦测试实例化并在 webdriver 中运行,它就无法工作。
有两个问题希望有经验的大侠解答一下:
1)如何让applescript使用webdriver的实例而不是常规的chrome窗口——如果能以某种方式解决这个问题,这是一个非常巧妙的解决方案
2)关于如何关闭上传对话框窗口的任何其他想法?
小程序
on run {input, parameters}
-- Click “Google Chrome” in the Dock.
delay 6.006100
set timeoutSeconds to 2.000000
set uiScript to "click UI Element \"Google Chrome\" of list 1 of application process \"Dock\""
my doWithTimeout( uiScript, timeoutSeconds )
return input
-- Click the ÒCancelÓ button.
delay 3.763318
set timeoutSeconds to 2.0
set uiScript to "click UI Element \"Cancel\" of sheet 1 of window \"PowerFLOW portal - Google Chrome\" of application process \"Chrome\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
end run
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
用于在测试中运行脚本的代码
try {
new ProcessBuilder("/path/to/the/script").start();
} catch (IOException e) {
e.printStackTrace();
}
}
除了尝试使用 applescript,我还尝试了“java 机器人类”,但无法关闭对话框窗口。
使用下面的代码片段,未注释的部分会转义整个 chrome 窗口(窗口变为“灰色”/非活动状态)而不是对话框窗口,这真的让我感到惊讶,因为我认为对话框窗口是当时的主要工作窗口。
注释的部分有效,但正如您可以想象的那样,如果测试在任何其他机器上运行,它是无用的,因为坐标仅特定于我的机器。
try {
Robot robot = new Robot();
//robot.mouseMove(906, 526);
//robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
//robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.keyPress(KeyEvent.VK_ESCAPE);
robot.keyRelease(KeyEvent.VK_ESCAPE);
} catch (AWTException e) {
e.printStackTrace();
}
该方法本身看起来就像这样
$$x("#ElementsCollection")
.findBy("text1")
.scrollIntoView(true)
.find(byXpath("#xpath")).val("text2")
.find(byXpath("#xpath") //this is the location of the <a> element mentioned above that needs to be clicked in order for <input type file> element to appear
.click();
$x("//input[@type=\"file\"]").sendKeys("/path/to/the/uploadedFile");
解决方案
如我所见,实现目标的原始复杂性是
该文件是一个隐藏的输入字段
并且仅在单击文件应该被“拖放”或从系统加载的区域后出现;
即——隐藏文件。如果我错了,请纠正我:)
但这应该不是问题,因为 Selenium WebDriver 的 sendKeys 命令适用于 type=file 的输入标记的隐藏元素。所以只是简单的 sendKeys 应该通过。Selenide 的 uploadFromClassPath 命令基于原始的 sendKeys - 所以它也应该通过。
这是一个简单的测试,表明上传文件不依赖于输入元素的可见性:
import org.junit.jupiter.api.Test;
import static com.codeborne.selenide.Condition.hidden;
import static com.codeborne.selenide.Condition.text;
import static com.codeborne.selenide.Selenide.*;
import static com.codeborne.selenide.Selenide.$;
public class TheInternetTest {
@Test
void fileUpload() {
// GIVEN
open("https://the-internet.herokuapp.com/upload");
executeJavaScript(
"document.getElementById('file-upload').style.display = 'none'"
);
$("#file-upload").shouldBe(hidden);
// WHEN
$("#file-upload").uploadFromClasspath("temp.txt");
$("#file-submit").click();
// THEN
$("#uploaded-files").shouldHave(text("temp.txt"));
}
}
在此处使用此代码检查完整的工作项目:https ://github.com/yashaka/selenide-file-upload-demo/blob/main/src/test/java/TheInternetTest.java
PS 编写 Web UI 测试时的常见最佳实践是“找到达到目标的简单方法,而不是在真实用户模拟的上下文中找到最佳方法”。这就是为什么我们试图绕过所有对被测应用程序失控的窗口。所以我的建议是——忘记苹果脚本,直接通过 selenium webdriver 处理输入文件。
推荐阅读
- azure - 我的客户应该如何授权我的服务器端应用程序访问他们的 Azure 资源?
- sql - 如果一列为空,则将另一列也替换为空
- python - 为什么断言在抽象类中不起作用?
- android - 过滤数据时是否需要 AsyncTask 来停止被阻止的 UI android?
- database - 如何在 mongodb 中正确展开我的数组
- json - 不使用 Ajax 直接访问 API 网关 - 如何构建 JSON
- arrays - 尝试访问元素附近的路径表达式无效
- javascript - JavaScript中的浮点乘法
- c# - c#'HttpContext'不包含'Current'的定义,无法读取我的Web应用程序上的发布值
- r - 如何使用两个参数向量评估函数值