PlaywrightはE2Eテストを行うためのツールですが、ブラウザを自動操作することができるので、作業の自動化にも使用できます。
JavascirptやPythonなどでもPlaywrightを使用できますが、playwright-goがあるので、GolangでもPlaywrightを使用できます。
Playwright for Go a browser automation library to control Chromium, Firefox and WebKit with a single API.
ファイルをアップロードする自動化を行うときに、input要素に対してはSetInputFilesが使用できるのですが、 input以外の要素だとSetInputFilesは動作しないため、別の方法でファイルをアップロードする必要があります。
テストアップロード環境の準備 #
ファイルをアップロードする環境をhtml、javascript、golangを使用して用意します。
下記のindex.html、main.js、main.goを同じパスに配置し、go run main.goでサーバーを起動します。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ファイルアップロード</title>
<style>
#drop-area {
width: 300px;
height: 200px;
border: 2px dashed #ccc;
text-align: center;
padding: 20px;
margin: 50px auto;
}
</style>
</head>
<body>
<div id="drop-area" ondragover="allowDrop(event)" ondrop="handleDrop(event)">
ファイルをここにドロップ
</div>
<script src="main.js"></script>
</body>
</html>
main.js
function allowDrop(event) {
event.preventDefault();
}
function handleDrop(event) {
event.preventDefault();
var files = event.dataTransfer.files;
if (files.length > 0) {
var file = files[0];
uploadFile(file);
}
}
function uploadFile(file) {
var formData = new FormData();
formData.append('file', file);
fetch('/upload', {
method: 'POST',
body: formData,
})
.then((response) => response.json())
.then((data) => {
console.log('File uploaded successfully:', data);
})
.catch((error) => {
console.error('Error uploading file:', error);
});
}
main.go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
http.HandleFunc("/upload", uploadHandler)
http.Handle("/", http.FileServer(http.Dir(".")))
port := 8080
fmt.Printf("Server is running on http://localhost:%d\n", port)
err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
if err != nil {
fmt.Println("Error starting server:", err)
}
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(1000000) // 1MB制限
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Println("Error retrieving the file:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
defer file.Close()
fmt.Printf("Received file: %+v\n", handler.Filename)
f, err := os.Create("./" + handler.Filename)
if err != nil {
fmt.Println("Error creating file:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
defer f.Close()
io.Copy(f, file)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"message": "File uploaded successfully"}`))
}
サーバーを起動してhttp://localhost:8080/
にアクセスすると、ブラウザに「ファイルをここにドロップ」が表示されます。
「ファイルをここにドロップ」と表示されているエリアに1MB以内のファイルをドラッグ&ドロップすると、サーバーにファイルがアップロードされます。
playwright-goでファイルをアップロード #
先ほどのindex.htmlだと、div要素のid="drop-area"
にファイルをドラッグ&ドロップするとファイルをアップロードできますが、input要素ではないのでplaywright-goのSetInputFilesだと動作しません。
<div id="drop-area" ondragover="allowDrop(event)" ondrop="handleDrop(event)">
ファイルをここにドロップ
</div>
下記のコードではChromeを使用して、SetInputFiles以外の方法でtest.txtファイルをアップロードします。
package main
import (
"encoding/base64"
"fmt"
"os"
"github.com/playwright-community/playwright-go"
)
func main() {
runOption := &playwright.RunOptions{
SkipInstallBrowsers: true,
}
if err := playwright.Install(runOption); err != nil {
panic(err)
}
pw, err := playwright.Run()
if err != nil {
panic(err)
}
defer pw.Stop()
contextOption := playwright.BrowserTypeLaunchPersistentContextOptions{
Channel: playwright.String("chrome"),
Headless: playwright.Bool(false),
Timeout: playwright.Float(0),
NoViewport: playwright.Bool(true),
}
// ユーザーディレクトリは絶対パスで指定する必要があります
userDataDir := `C:\userDataDir`
browser, err := pw.Chromium.LaunchPersistentContext(userDataDir, contextOption)
if err != nil {
panic(err)
}
defer browser.Close()
page := browser.Pages()[0]
defer page.Close()
page.Goto("http://localhost:8080")
bytes, err := os.ReadFile("test.txt")
if err != nil {
panic(err)
}
fileBase64 := base64.StdEncoding.EncodeToString(bytes)
js := `
(data) => {
const dt = new DataTransfer();
// Convert the binary string to a hexadecimal string
const hexString = Uint8Array.from(atob(data), c => c.charCodeAt(0));
const file = new File([hexString], 'test.txt', { type: 'text/plain' });
dt.items.add(file);
return dt;
}
`
handle, err := page.EvaluateHandle(js, fileBase64)
if err != nil {
panic(err)
}
element := page.Locator("#drop-area")
if err := element.DispatchEvent("drop", map[string]interface{}{"dataTransfer": handle}); err != nil {
panic(err)
}
fmt.Println("ファイルをアップロードしました。")
}
コードを実行するとサーバー側のターミナルで「Received file: test.txt」と表示されて、サーバーを起動しているパスにtest.txtがアップロードされます。
Server is running on http://localhost:8080
Received file: test.txt