LoginSignup
0
0

More than 1 year has passed since last update.

JestでOrbitDBを使うテストをなんとかしてやった

Last updated at Posted at 2021-09-03

背景

卒業研究でWebフロントエンドで動作する分散型の図書館WebアプリをNuxt.js+TypeScriptで開発しています。このWebアプリではデータベースとしてIPFS上にデータを保管するOrbitDBを採用しており、ブラウザ上で直接P2Pネットワークに参加して接続を確立してDBをやり取りします。OrbitDB/IPFSを利用することで、複数の図書館で共通のデータベースを扱うことができるため、蔵書や貸し出し状態を容易にやり取りでき、いろんな点で面白い/便利なんじゃないかと思いはじめた研究です。

これを作るためには複数のデータベースを扱う必要が出てくるため、大量のDAO、model、Typeを定義しました。これらすべてをブラウザ上でいちいち手動で確認はしていられません。 なので、使うのは初めてですが、Jestを使って テストをしたくなりました。

テストしたい内容

beforeAllの内容

全体テスト前にIPFSインスタンスを作成、IPFSインスタンスを渡してOrbitDBインスタンスを作成
BibliographyDaoを作成、BibliographyDaoを初期化(コンストラクタ無いでasyncが使えなかったのでやむおえず分離)

testの内容

蔵書情報モデルを作成
蔵書情報をOrbitDBに追加
追加結果などログ表示

実際テストしてみた

ReferenceError: TextDecoder is not defined.

image.png
と言われて動かなかった。検索したところ既にissueと記事があった。jsdomじゃ組み込みのTextDecoderが無いよっていう話らしい。

どうやら setupJest.ts とやらを作って jest起動時に細工をすればいいらしいので jest.config.jsに 下記のように追記した

{
    ...
    setupFilesAfterEnv: ['<rootDir>/test/setupJest.ts'],
    testEnvironment: 'jsdom'
}

そして setupJest.tsの中身だが、Zennの記事通りだと上手くいかなかったので
Jestに立っていたIssueを読んで下記のようにした。

// Polyfill for encoding which isn't present globally in jsdom
if (typeof global.TextEncoder === 'undefined') {
  global.TextEncoder = require('util').TextEncoder
}

if (typeof global.TextDecoder === 'undefined') {
  global.TextDecoder = require('util').TextDecoder
}

これで完結だと思ったら 新しいエラーが出た

Unknown type, must be binary type

image.png

これがかなり困った。というのもググってもパット出てこない。
ヒットしたにはしたものの gitter.imのチャットログ的なもので、いつあった発言なのか どこまで遡れば出るかわからず 断念した。
image.png

仕方がないので エラーの at... を追ってみたところ ここの inputに Uint8Array でなくBuffer が入っていて バイナリ型じゃない!!って怒られているのが原因だった。試しに instanceof Uint8Arrayinstanceof Buffer にしたら次のコードまで進むが、また同様に Uint8Arrayでなく Bufferだから バイナリ型じゃない!! って怒られてしまった。 (js-ipfsでは 昔Buffer駆逐運動 があったらしく 元々Bufferで書かれていたところは全部Uint8Arrayになっている、独自に変えちゃうのは無謀な気がするのでやめた)
image.png

そこでUint8ArrayとBufferの変換について調べるとNode.jsでは Uint8ArrayはBufferのサブクラスで相互利用できる( buffer instanceof Uint8Array === true )よ的なことが書いてあった。汎用的なUint8Array以前にNode.js独自のBufferがあったという歴史的経緯からこうなったらしい。

じゃあなんで動かないのって調べたら 2017年からある、Jestのbuffer instanceof Uint8Array を破壊するっていうバグが原因だった

ここで書いてあった通りに下記をjest.config.tsに追加して元々あるUint8Arrayをグローバルに登録し、各テスト内で 元々のUint8Arrayを見えるようにした。

  globals: {
    Uint8Array
  },

これで今度こそ動く、と思ったら新しいエラーが出た

ReferenceError: crypto is not defined

image.png

どうやら window.crypto も jsdomでは組み込みではないよ っていう話らしい。
issueの下の方を読んで下記を setupJest.ts に追加した

import { Crypto } from "@peculiar/webcrypto"

global.crypto = new Crypto()

これでなんとか動くはず。

動いた

image.png

完走した感想

結構苦戦したがこれで Jest(jsdom)で動いてくれた。テストをじゃんじゃん書こうと思う。ただよく見ると、testEnvironmentjsdomではなくnodeに変えたらいいとも書いてあったので、nodeに変えてみたところ cryptoのエラーだけで他はいじらなくても動いてくれた。元々jestの資料に載っていたようなので、公式ドキュメントを最初に読もうねという教訓を覚えた。

その他補足資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0