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