【qp】File API利用箇所をjestでテストする
9月14日の日報です。今日はしんどかった。
File API 利用箇所のテストを書く
いま仮に、こんなコードがあるとしてですね。
/** * read an image file and return contents * @param {File} file a file object * @return {Promise<string>} base64 data */ export const readFile = async (file: File): Promise<string> => { // create reader const reader = new FileReader(); // return promise return new Promise<string>((resolve, reject) => { // event handler reader.onload = (event: ProgressEvent) => { // get result const target = event.target as FileReader | null; // reject if target is blank if (!target) { return reject(new Error("readFile error: event.target is blank")); } // return result const result = target.result as string; resolve(result); }; // read as a data url reader.readAsDataURL(file); }); };
テストはどう書くの? というと、こう書きます。v10で実行しているので他だと動かないかも。
import { readFile } from "~/store/uploader"; import fs from "fs"; const getSampleBuffer = (): Buffer => { const path = `${__dirname}/test-neko.png`; return fs.readFileSync(path); }; describe("readFile", () => { let file: File; beforeEach(() => { // create file object file = new File([getSampleBuffer().buffer], "test-neko.png", { type: "image/png" }); }); it("returns data string (base64 format) which file-reader returns", async () => { const result = await readFile(file); expect(result).toEqual( "data:image/png;base64,iVBOR...5CYII=" // 長すぎ中略 ); }); });
今回はテストファイルと同じ場所にサンプル画像を置いています。こんなやつです。
再エンコードされていてbase64の値は一致しないかもしれませんが、まあその辺は適当に。
何故これで動くのか
知らんって感じなのですが、いくつかポイントはあります。
まず node.js Buffer
が Uint8Array を継承していることです (詳しくはここ)1。
そしてUint8Arrayには buffer
という読取専用プロパティがあり、ここから ArrayBuffer
を取得できます。
Uint8Array.prototype.buffer [読取専用]
Uint8Array オブジェクトによって参照されるArrayBufferを返します。構築時に設定され、読取専用となります。https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
このプロパティはもちろん fs
で取得した Buffer
にもあります。つまり buffer.buffer
です。なんか分かりにくいですね… まあいいけど。
ともかく、ここから ArrayBuffer
が手に入ります。そしてこれがそのままFileコンストラクタで使えます。
var myFile = new File(bits, name[, options]);
bits
ArrayBuffer、ArrayBufferView、Blob、DOMString オブジェクト、もしくはこれらが混合したArrayです。これはUTF-8でエンコードされたファイルの内容です。
つまり、こうです2。[buffer.buffer]
として配列にする必要があるので注意してください。配列の配列ってなんかワクワクしますよね。
const buffer = fs.readFileSync(path); new File([buffer.buffer], "test-neko.png", { type: "image/png" });
あとはこれを渡してやればテスト可能です。最初は FileReader
からモックにする必要があるかと思ったのですが、特にそんなことはありませんでした。 File
だけ作って渡してやればいいみたいです。
割と簡単にFile API利用箇所をテスト可能になりました。めでたしめでたし3。