如何使用 Selenium 和 JavaScript 自動執行隱藏和唯讀輸入
1. 概述
一開始,使用 Selenium 與網頁表單互動似乎很簡單。我們用sendKeys()輸入文本,點擊單選按鈕,提交表單,一切都運行流暢。但是,一旦我們引入隱藏輸入框、唯讀欄位或由 JavaScript 動態填入的值,Selenium 的常規方法就開始顯得力不從心了。
在本教程中,我們將使用 Spring Boot 和 Selenium 完成一個完整的實際專案建置。我們將了解為什麼有時需要使用 JavaScript 直接設定輸入元素的 value 屬性。我們將建立後端應用程序,公開表單,並使用 Selenium 實現自動化。最後,我們將驗證伺服器是否正確接收所有值,包括隱藏值。
2.當我們輸入文字時,Selenium 究竟做了什麼?
Selenium 的設計初衷是模擬真實的使用者互動。當我們呼叫sendKeys()函數時,Selenium 並不會憑空賦值;它會觸發鍵盤事件,就像真人打字一樣。正因如此,它無法與人無法實際觸摸的對象進行交互,例如隱藏的輸入框、禁用的文本框或由後台腳本嚴格控制的字段。
這些元素並非設計用於直接使用者互動。然而,瀏覽器仍然會將它們隨表單一起提交,這意味著我們可以透過程式設定它們的值。為此,我們需要跳脫 Selenium 的使用者級 API,直接使用 JavaScript 操作 DOM。
3. Maven 依賴項
在編寫任何程式碼之前,我們需要正確的依賴項。我們將使用Selenium 4 :
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
該軟體包整合了 Selenium WebDriver API,可實現無縫的 Web 自動化。它為各種瀏覽器驅動程式提供廣泛的支援。此外,它還提供了諸如JavascriptExecutor等用於執行高階任務的實用工具。它還包含完善的等待機制來處理同步。最後,全面的工具可協助我們有效管理瀏覽器操作和視窗導覽。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
我們在專案中新增spring-boot-starter-web依賴項來處理 HTTP 請求。這會告訴 Spring Boot 引入所有必要的工具,包括 Spring MVC 框架和嵌入式 Tomcat 伺服器。
4. Spring Boot 應用程式設定
現在讓我們來設定用於提供 HTML 頁面的後端:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
它會啟動一個嵌入式 Web 伺服器,並幫助初始化 Spring 應用程式上下文。此外,它還會使localhost:8080上的 HTTP 端點可用。此應用程式必須在 Selenium 啟動之前執行。 Selenium 不會建立頁面,而是檢查一個已運行的頁面。
4.1控制器層:資料服務與接收
讓我們來建立用於處理 HTML 頁面的後端。我們定義一個控制器,用於處理表單並接收提交的值:
@Controller
public class DemoController {
@GetMapping("/demo")
public String showForm() {
return "index";
}
@PostMapping(value = "/submit")
public String handleSubmit(
@RequestParam String username,
@RequestParam String password,
@RequestParam String gender,
@RequestParam String dateOfBirth,
@RequestParam String hiddenInput
) {
System.out.println("Username: "+username);
System.out.println("Password: "+password);
System.out.println("Gender: "+gender);
System.out.println("DateOfBirth: "+dateOfBirth);
System.out.println("HiddenInput: "+hiddenInput);
return "redirect:/result.html";
}
}
在這個程式碼片段中,我們透過使用@Controller註解創建了一個 Web 控制器。它的結構旨在處理兩個不同的步驟:首先,我們在/demo端點使用了@GetMapping註解,它會傳回「index」視圖,以便向使用者顯示初始表單。第二部分是 ` /submit端點的@PostMapping註解,實際的資料收集(稍後將由 Selenium 設定)發生在這裡。
我們使用@RequestParam註解從傳入的請求中自動提取特定值,例如使用者名稱、密碼,甚至是隱藏的輸入框,並將它們對應到我們的方法變數中。我們將這些資訊列印到控制台以驗證是否已收到數據,然後透過將瀏覽器重新導向到結果頁面來完成工作流程。
這種簡潔的方法可以防止使用者意外重複提交表單。控制台輸出作為我們的驗證機制。如果此處出現數值,則表示 Selenium 的工作已正確完成。所有這些端點都將由 Selenium 直接呼叫。
4.2. HTML 表單:Selenium 互動的地方
讓我們看看 Selenium 會自動執行哪個頁面:
<!DOCTYPE html>
<html>
<head>
<title>Selenium Input Demo</title>
</head>
<body>
<h2>Demo Form</h2>
<form action="/submit" method="post">
<input type="hidden" id="hiddenInput" name="hiddenInput" value=""/>
<label>Username</label><br>
<input type="text" id="username" name="username"><br><br>
<label>Password</label><br>
<input type="password" id="password" name="password"><br><br>
<label>Gender</label><br>
<input type="radio" name="gender" value="male"> Male
<input type="radio" name="gender" value="female"> Female<br><br>
<label>Date of Birth</label><br>
<input type="date" id="dob" name="dateOfBirth"><br><br>
<button type="submit" id="submitBtn">Submit</button>
</form>
</body>
</html>
這段 HTML 程式碼片段配置了指向/submit端點的 POST 方法,確保資料透過請求體而非 URL 安全地傳輸。我們新增了多種輸入類型,例如用於儲存背景元資料的隱藏欄位、用於輸入憑證的標準文字方塊和密碼框,以及用於清晰選擇性別的單選按鈕。
它還內建了一個日期選擇器,以保持輸入格式的一致性,所有這些都透過一個簡單的提交按鈕觸發,該按鈕會啟動我們剛才討論的後端邏輯。這個隱藏的輸入框是我們Selenium挑戰的核心。
4.3. Selenium自動化:填寫表單
以下是所有 Selenium 自動化邏輯,它們位於一個程式碼區塊中,在 Spring Boot 應用程式運行後獨立執行:
public class SeleniumValue {
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
driver.manage()
.timeouts()
.implicitlyWait(Duration.ofSeconds(5));
driver.manage()
.window()
.maximize();
driver.get("http://localhost:8080/index.html");
driver.findElement(By.id("username"))
.sendKeys("selenium_user");
driver.findElement(By.id("password"))
.sendKeys("secret123");
driver.findElement(By.cssSelector("input[name='gender'][value='male']"))
.click();
driver.findElement(By.id("dob"))
.sendKeys("15-08-2025");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.getElementById('hiddenInput').value='input-from-selenium';");
Thread.sleep(4000);
driver.findElement(By.id("submitBtn"))
.click();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(8));
wait.until(ExpectedConditions.urlContains("/result"));
Thread.sleep(4000);
driver.quit();
}
}
首先,我們啟動 Chrome 瀏覽器並配置逾時時間,這樣 Selenium 就會等待元素出現,而不是立即失敗。接下來,我們載入已執行的 Spring Boot 應用程式提供的頁面。 Selenium 不會啟動應用,它只會檢查現有的內容。我們使用標準的 Selenium 命令,例如sendKeys()和click()來管理可見字段,例如使用者名稱、密碼、性別和出生日期。
接下來是設定隱藏輸入框的關鍵步驟。由於sendKeys()無法操作隱藏元素,我們將驅動程式強制轉換為JavascriptExecutor類型,並直接更新 DOM。透過 JavaScript 設定值並非權宜之計,而是一種有意為之的技巧。在當今的應用程式中,我們經常會遇到用於儲存 CSRF 令牌、會話元資料或功能標誌等資訊的隱藏欄位。
我們也使用Thread.sleep()添加了一些策略性的暫停,以便在觸發提交按鈕之前即時觀察自動化流程的執行情況。所有值設定完畢後,我們提交表單並等待導航確認 POST 請求已處理完畢。最後,我們正常關閉瀏覽器。
4.4 輸出
首先,我們將執行DemoApplication.java,然後觸發SeleniumValue.java. The中的main()函數。以下是應用程式控制台中將顯示的輸出:
5. 結論
我們知道 Selenium 的標準工具不會觸及隱藏元素,因為它們並非設計用於人機互動。然而,瀏覽器仍然會在表單提交中包含這些元素。我們可以使用JavaScript來彌補這個缺陷。透過直接操作 DOM,我們可以確保自動化測試覆蓋伺服器期望的所有數據,從而使測試更加健全和貼近實際。
在本教程中,我們結合了 Spring Boot 和 Selenium,創造了一個逼真的生產級環境。這個環境向我們展示如何在傳統自動化方法無法處理時,精準地處理隱藏的輸入值。由於我們理解 Selenium 模擬的是人類行為,因此也明白它為何限制我們只能操作可見元素。這種理解有助於我們認識到JavascriptExecutor是我們工具箱中處理其他所有操作的關鍵工具。
與往常一樣,本文的程式碼可在 GitHub 上找到。