最近、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
を知ってるかどうかで世界が変わる。
まとめ
今回紹介したパターンをざっくり振り返ると:
- SDKで直接アップロード → 手軽で便利
- 署名付きURL → 実サービスに近い
- UIからアップロード → 本番同様のE2E確認
- テストデータを事前配置 → CI/CD向き
- .env管理で安全に認証
- CI環境はSecretsかOIDCで
- 大容量ならマルチパート
私自身、PlaywrightのテストにS3を絡めてみて「ただのE2Eテストなのに、AWSインフラの知識が自然とついてくる」のが面白かったです。
もし同じように悩んでいる人がいたら、この記事を参考に「自分の現場に合うパターン」を選んでみてください。