QA

AWS S3にファイルをアップロードするPlaywrightコードのパターン集

最近、E2Eテストの自動化で「ファイルをS3にアップロードする必要がある」場面に遭遇しました。
普通なら「AWS CLIでぽちっとアップロードすればいいじゃん」で終わるのですが、Playwrightでテストシナリオを回していると、どうしても「テストコードの中でS3にファイルを置きたい」とか「フロントエンドが署名付きURLを使ってS3に直アップロードする流れを再現したい」みたいなニーズが出てくるんですよね。

この記事では、私が実際に試してみて「これ、便利だな」と感じた S3アップロードのパターン集 をまとめておきます。加えて、ちょっと応用的な .env管理 / CI環境での安全なキー設定 / マルチパートアップロード についても触れるので、PlaywrightユーザーやAWS好きの方には参考になればいいなと思います。

1. SDKを使ってシンプルにアップロードする

やっぱり最初に触れるのは「王道」。AWS SDKをそのままテストコードの中で呼んでしまうパターンです。

import { test } from '@playwright/test';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import fs from 'fs';

test('S3へ直接アップロード', async () => {
  const s3 = new S3Client({
    region: 'ap-northeast-1',
    credentials: {
      accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
    },
  });

  const filePath = 'tests/fixtures/sample.txt';
  const fileContent = fs.readFileSync(filePath);

  await s3.send(new PutObjectCommand({
    Bucket: 'my-bucket',
    Key: 'uploads/sample.txt',
    Body: fileContent,
    ContentType: 'text/plain',
  }));
});

 

感想

  • 正直めちゃくちゃシンプル。
  • 「テスト開始前にファイルを置いておきたい」とか「テスト完了後にファイルを掃除したい」みたいな用途に相性バツグン。
  • 一方で「実際のフロントからのアップロード」をシミュレートするわけではないので、あくまで裏方の補助的な感じ。

表にするとこんなイメージ↓

メリット デメリット
実装が簡単 実ユーザー操作とは乖離
テスト準備や掃除に便利 S3の権限キーを直に使う必要がある

 

2. 署名付きURL(Presigned URL)を使う

次に好きなのがこのパターン。私は「これが実際の現場っぽい」と思いました。
バックエンドで一度署名付きURLを発行して、それを使ってPUTリクエストでS3に直アップロードする方法です。

import { test, expect } from '@playwright/test';
import fetch from 'node-fetch';

test('署名付きURLでS3にアップロード', async () => {
  const apiRes = await fetch('http://localhost:3000/api/presigned-url');
  const { url } = await apiRes.json();

  const fileContent = Buffer.from('Hello from Playwright!');

  const uploadRes = await fetch(url, {
    method: 'PUT',
    body: fileContent,
    headers: {
      'Content-Type': 'text/plain',
    },
  });

  expect(uploadRes.status).toBe(200);
});

 

感想

  • 実際のサービスがやっている流れそのものなので「テストしている感」が強い。
  • 認証情報をフロントに渡さなくても良い点も安心。
  • バックエンド側に「署名付きURLを発行するAPI」が必要なので、仕込みがちょっと面倒。

 

3. PlaywrightでUIからファイルアップロード

今度は「ブラウザを実際に動かす」パターン。
<input type="file"> にファイルをセット → フロント経由でサーバーに渡し → S3に保存、という流れをそのままE2Eで検証できます。

import { test, expect } from '@playwright/test';
import path from 'path';

test('UIからS3へアップロード', async ({ page }) => {
  await page.goto('http://localhost:3000/upload');
  const filePath = path.resolve('tests/fixtures/sample.txt');

  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  const fileChooser = await fileChooserPromise;
  await fileChooser.setFiles(filePath);

  await page.click('#submit-button');
  await expect(page.locator('#upload-result')).toHaveText('Upload successful');
});

感想

  • 実ユーザーの操作に近いので「本番同様の動作確認」ができるのが最高。
  • ただしテストが遅くなるのは仕方ない。
  • 「バックエンドがS3に転送する部分」はモニタリング必須。

 

4. 応用:テストデータをS3に事前配置する

CI/CDで便利なのがこれ。
テスト前にS3に必要な画像やデータを置いてから、Playwrightでその存在を前提にシナリオを走らせるやつ。

test.beforeAll(async () => {
  const s3 = new S3Client({ region: 'ap-northeast-1' });
  const fileContent = fs.readFileSync('tests/fixtures/avatar.png');
  await s3.send(new PutObjectCommand({
    Bucket: 'my-bucket',
    Key: 'test/avatar.png',
    Body: fileContent,
    ContentType: 'image/png',
  }));
});

 

5. AWS SDKの認証を.envで管理する

ここから応用編。
私も最初、認証情報をコードにベタ書きしてしまって「おっとヤバイ」となりました。笑
結論としては dotenvで環境変数管理 が一番ラクで安全。

.env例

AWS_ACCESS_KEY_ID=xxxxxxxx
AWS_SECRET_ACCESS_KEY=yyyyyyyy
AWS_REGION=ap-northeast-1

Playwrightの設定

import dotenv from 'dotenv';
dotenv.config();

こうしておけば、GitHubにコードを公開しても安心。
「.envをコミットしない」鉄則を忘れなければ大丈夫。

6. CI環境での安全なキー設定

ローカルでは.envで良いけど、CI(GitHub ActionsやGitLab CI)ではどうするか?

私のおすすめは以下の3パターン:

  • GitHub ActionsのSecretsにキーを登録 → 環境変数に注入
  • IAM Roleを使ってEC2やLambdaの環境に自動付与
  • OIDCでロール引き受け → Secretsすら不要にする

特に最近は「Secretsを使わない」方向(OIDC認証)がトレンドっぽい。
「キーをCIに置かない」って、精神衛生的にもめっちゃ安心です。

 

7. 大容量ファイルのマルチパートアップロード

最後にちょっとマニアックな応用。
動画や数GBのデータを扱うときは「マルチパートアップロード」を使わないとタイムアウト地獄になります。

import { Upload } from "@aws-sdk/lib-storage";
import { S3Client } from "@aws-sdk/client-s3";
import fs from 'fs';

const s3 = new S3Client({ region: 'ap-northeast-1' });
const fileStream = fs.createReadStream('bigfile.zip');

const upload = new Upload({
  client: s3,
  params: {
    Bucket: 'my-bucket',
    Key: 'bigfile.zip',
    Body: fileStream,
  },
});

await upload.done();

感想

  • 正直これは「本格的なシステム開発寄り」。
  • でも「テストででかいファイルを扱う必要がある」なら必須テクニック。
  • @aws-sdk/lib-storage を知ってるかどうかで世界が変わる。

 

まとめ

今回紹介したパターンをざっくり振り返ると:

  1. SDKで直接アップロード → 手軽で便利
  2. 署名付きURL → 実サービスに近い
  3. UIからアップロード → 本番同様のE2E確認
  4. テストデータを事前配置 → CI/CD向き
  5. .env管理で安全に認証
  6. CI環境はSecretsかOIDCで
  7. 大容量ならマルチパート

私自身、PlaywrightのテストにS3を絡めてみて「ただのE2Eテストなのに、AWSインフラの知識が自然とついてくる」のが面白かったです。
もし同じように悩んでいる人がいたら、この記事を参考に「自分の現場に合うパターン」を選んでみてください。

 

ABOUT ME
りん
このブログでは、Web開発やプログラミングに関する情報を中心に、私が日々感じたことや学んだことをシェアしています。技術と生活の両方を楽しめるブログを目指して、日常で触れた出来事や本、ゲームの話題も取り入れています。気軽に覗いて、少しでも役立つ情報や楽しいひとときを見つけてもらえたら嬉しいです。