Go-Rod自用案例 #1 測試多組賬號登入

J_Coder發表於2024-03-24

使用場景

本樣例用於在給定的HTML檔案中(簡單的登入註冊),測試多組賬號密碼是否能夠成功登入,並列印出登入結果。

前端程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Page</title>
    <script>
        // 定義登入函式
        function login() {
            // 獲取使用者名稱和密碼
            var username = document.getElementById("username").value;
            var password = document.getElementById("password").value;
            var resultDiv = document.getElementById("login-result");

            // 檢查使用者名稱和密碼(此示例中為了簡單,直接使用靜態的使用者名稱和密碼)
            if(username === "admin" && password === "password") {
                // 登入成功
                resultDiv.innerText = "登入成功!";
                resultDiv.style.color = "green";
            } else {
                // 登入失敗
                resultDiv.innerText = "登入失敗:使用者名稱或密碼錯誤。";
                resultDiv.style.color = "red";
            }

            // 防止表單實際提交
            return false;
        }
    </script>
</head>
<body>
<h2>登入頁面</h2>
<!-- 建立登入表單 -->
<form onsubmit="return login();">
    <label for="username">使用者名稱:</label><br>
    <input type="text" id="username" name="username" required><br>
    <label for="password">密碼:</label><br>
    <input type="password" id="password" name="password" required><br><br>
    <input type="submit" value="登入">
</form>
<!-- 新增一個元素用來顯示登入結果 -->
<div id="login-result"></div>
</body>
</html>

這是一個最簡單的登入表單,使用者進行提交時,在idlogin-result的元素中顯示登入的結果。

後端程式碼

package main

import (
    "fmt"
    "github.com/go-rod/rod"
    "time"
)

// 測試的賬號密碼組
var credentials = []struct {
    Username string
    Password string
}{
    {"admin", "password"},  // 應該成功
    {"user", "123456"},     // 應該失敗
    {"admin", "wrongpass"}, // 應該失敗
    // 可以新增更多的測試組
}

func main() {
    browser := rod.New().MustConnect().MustPage()
    defer browser.MustClose()

    for _, cred := range credentials {
       testLogin(browser, cred.Username, cred.Password)
       time.Sleep(1 * time.Second) // 給頁面一些時間來處理登入並顯示結果
    }
}

func testLogin(page *rod.Page, username, password string) {
    page.MustNavigate("http://localhost:63344/LoginTese/LoginTese/login.html")
    page.MustElement("#username").MustInput(username)
    page.MustElement("#password").MustInput(password)
    page.MustElement("input[type='submit']").MustClick()

    // 假設登入結果會顯示在id為"login-result"的元素中
    // 使用Racer來等待頁面載入或者特定元素出現
    resultSelector := "#login-result"
    page.Race().Element(resultSelector).MustHandle(func(e *rod.Element) {
       resultText, err := e.Text()
       if err != nil {
          fmt.Println("Error getting result text:", err)
          return
       }
       fmt.Printf("Login result for '%s': %s\n", username, resultText)
    }).MustDo()

    // 可以根據需要調整等待時間
    time.Sleep(2 * time.Second)
}

我們詳細來看一下後端程式碼,由於是剛剛入門,我們把每一行程式碼詳細地分析一下,方便日後再次使用。

var credentials = []struct {
    Username string
    Password string
}{
    {"admin", "password"},  // 應該成功
    {"user", "123456"},     // 應該失敗
    {"admin", "wrongpass"}, // 應該失敗
    // 可以新增更多的測試組
}
  • 這段 Go 語言的程式碼定義了一個名為 credentials 的變數,它是一個由結構體組成的切片。每個結構體包含兩個欄位:UsernamePassword,分別代表登入所需的使用者名稱和密碼。
  • 變數定義、結構體定義比較好理解,這裡不展開說了,我們著重說一下切片初始化。[]struct{...}{...} 這部分不僅宣告瞭一個結構體切片型別,還透過 {...} 對其進行了初始化。切片中的每個元素都是透過 {} 來初始化,其中 UsernamePassword 欄位被賦予相應的值。
browser := rod.New().MustConnect().MustPage()
    defer browser.MustClose()

啟動瀏覽器程式建立連線,確保程式終止前執行關閉,沒有什麼可以細說的。

for _, cred := range credentials {
       testLogin(browser, cred.Username, cred.Password)
       time.Sleep(1 * time.Second) // 給頁面一些時間來處理登入並顯示結果
    }
  • 遍歷credentials,傳入瀏覽器、使用者名稱、密碼三個引數,執行testLogin函式進行測試。
  • 在頁面稍做停留,給頁面時間來處理並顯示結果。
func testLogin(page *rod.Page, username, password string) {
    page.MustNavigate("http://localhost:63344/LoginTese/LoginTese/login.html")
    page.MustElement("#username").MustInput(username)
    page.MustElement("#password").MustInput(password)
    page.MustElement("input[type='submit']").MustClick()

    // 假設登入結果會顯示在id為"login-result"的元素中
    // 使用Racer來等待頁面載入或者特定元素出現
    resultSelector := "#login-result"
    page.Race().Element(resultSelector).MustHandle(func(e *rod.Element) {
       resultText, err := e.Text()
       if err != nil {
          fmt.Println("Error getting result text:", err)
          return
       }
       fmt.Printf("Login result for '%s': %s\n", username, resultText)
    }).MustDo()

    // 可以根據需要調整等待時間
    time.Sleep(2 * time.Second)
}
  • 來看一下testLogin內的內容
    • page.MustNavigate("http://localhost:63344/LoginTese/LoginTese/login.html"):導航瀏覽器到提供的URL地址。
    • page.MustElement("#username").MustInput(username):在id為username的元素內傳入username的值。
    • page.MustElement("#password").MustInput(password):在id為password的元素哪傳入password的值。
    • page.MustElement("input[type='submit']").MustClick():尋找第一個typesubmitinput元素,並點選它。
    • page.Race() 建立了一個競態條件(race condition),在這個條件下,多個事件或元素被並行等待。Race 是 go-rod 庫中的一個功能,允許開發者定義一系列可能發生的事件,然後執行與首個發生的事件相關的回撥函式。
    • .Element(resultSelector)Race 的一個方法,用於指定一個 CSS 選擇器來尋找頁面上的元素。resultSelector 是一個字串變數,其中包含了 CSS 選擇器的值。這個選擇器用來找到顯示登入結果的元素。
    • .MustHandle(func(e *rod.Element)) 為找到的元素定義了一個處理函式。如果元素被成功找到,這個處理函式將被呼叫。在這個處理函式中,e 是指向找到的元素的指標。
    • 在處理函式內部,e.Text() 被呼叫來獲取元素的文字內容。這個文字內容預期包含登入的結果(例如,“登入成功”或“登入失敗:使用者名稱或密碼錯誤”)。
    • .MustDo() 是必須呼叫的方法,它觸發了前面定義的 Race 條件的執行。沒有這個呼叫,之前設定的等待條件和處理函式都不會被實際執行。

相關文章