メールアーカイバーには、重要な意味で失敗しうる方法がただ一つあります。頼んでもいないのに、あなたのメールに何かをしてしまうことです。メッセージを既読にする、間違ったフォルダに振り分ける、間違ったものを削除する。だからこそ、 MailVault のすべての機能は同じ手順で出荷されます。マシンが実際のアプリケーションを開き、人が操作するのと同じようにその機能を実行し、実際の画面から結果を読み取った後にだけ。
これは、その仕組みについての進捗報告です。というのも、機能そのものより、この仕組みのほうがずっと面白いことになったからです。
テストはアプリを使う。シミュレートはしない。
MailVault は Tauri アプリケーションです。IMAP 処理を担う Rust バックエンドと、ネイティブ webview 内で動く React インターフェースから成ります。Tauri にはここであまり知られていない強みがあります。アプリをその webdriver 機能付きでビルドすれば、ブラウザと同じように実際のアプリケーションをリモート操作できるようになります。私たちのスイートは、 wry ケーパビリティを備えた WebdriverIO 上で、 tauri-driverを通して、実際にコンパイルされたバイナリに対して動作します。
この違いは重要です。コンポーネントテストは、架空のブラウザの中にリストを描画し、仮想的な出力に対してアサーションを行います。私たちのエンドツーエンドテストは、ユーザーが実際に目にするのと同じウィンドウを起動し、同じ行が描画されるのを待ち、同じボタンをクリックし、そのうえでインターフェースとサーバー上のメールが実際に何を示しているかを確認します。今週実施した、選択操作バーのテストからの抜粋です。
Selection Action Bar effects
✓ marks a selected row as read and repaints it
✓ marks a row back as unread
✓ marks several selected rows as read in one action
✓ archives a selected row and flips its source icon to local
✓ unarchives it again
✓ moves a selected row to another folder and drops it from the list
✓ deletes a selected row from the server and drops it from the list
7 passing (833ms)
どの行も完全な往復です。インターフェース上のクリック、Rust バックエンドの呼び出し、サーバーとの IMAP 通信、そしてテストが自分の目で確かめる再描画。スイートが「アーカイブすると送信元アイコンがローカルに変わる」と言うとき、それはマシンが実際にそのアイコンの変化を見届けたということです。
メールサーバーは実行のたびに生まれて死ぬ
これらはどれも実アカウントに触れません。実行のたびに、ローカルポート上で新しいモック IMAP サーバーが立ち上がり、既知の2つのアカウントがシードされます。これにより、スイートは単一のハッピーパスだけでなく、アカウント切り替えや統合受信トレイも検証できます。片方のアカウントにはあえて700通のメッセージを持たせています。これはアプリの読み込みウィンドウ2つ分より多く、常に本当の意味で部分的にしか読み込まれていないメールボックスが存在することになります。ページネーションのバグが潜むのは、まさにこの状態です。
アプリ自体は、実行のために作られた使い捨てのホームディレクトリを向いています。アーカイブも、設定も、ローカルデータベースも、すべて1分前まで存在しなかったフォルダに収まり、実行が終われば削除されます。認証情報も、ネットワークも、実際のメールも、このプロセスの近くには一切ありません。
決定性がもう一つの理由です。実際のメールサーバーは、あなたを制限してきます。Gmail は IMAP ダウンロードを1日 2,500 MB に制限しており、これについては 前回のフィールドノートで書きました。そして、どのプロバイダも、テストスイートには許容できないほど気まぐれです。モックサーバーは、シナリオが指示する通りのことを、毎回ミリ秒単位で正確に行います。このスイートの仕事は、私たちのバグを捕まえることであって、Google の天気具合を追うことではありません。
何かが本当に大切なものを預かっているかのようにテストされたメールクライアント。 MailVault はあなたのメールを、自分のディスク上の標準的なファイルにアーカイブします。そして、どのリリースもまずこのスイートを突破しなければなりません。
MailVault にアクセスしてください →机の下のマシンは、私たちが作業しているマシンではない
ここからが、日々の作業を変えた部分です。完全なエンドツーエンドの実行は重いものです。React フロントエンドをビルドし、Rust バックエンドをコンパイルし、そのうえでアプリケーションを何十回も開いては閉じます。スペックファイルごとに新しいセッションが1つで、connected スイートだけでも14個のスペックファイルがあります。これを開発マシン上で実行すると、CPU があなたの存在を忘れる間、ウィンドウにフォーカスを奪われ続けることになります。その間、誰もコードを書けません。
だから、実行はそこでは行われません。小型の Apple Silicon 搭載 Mac mini が、ローカルネットワーク上で他に何もせずに待機しています。アクセスできるのは SSH 経由、しかもネットワーク内からだけで、リポジトリとツールチェーンのクローンを保持しています。機能の準備が整うと、実行は1つのコマンドで mini に送られ、開発マシンは次のものを作る作業に戻ります。その間、mini は今の機能をビルドし、起動し、クリックして回ります。
この2つの作業は、交互に行われるのではなく重なり合います。小さなことのように聞こえますが、機能開発中に1日に何回スイートが実行されるかを数えてみれば、その意味がわかります。mini 上の各セッションは、毎回まっさらな状態と新しいサーバーでアプリをコールドスタートします。これは、アプリが書かれたマシンよりも都合よく遅いハードウェア上での、コールドスタートの正直なテストでもあります。ある機能が mini 上でもたつくなら、それは mini の問題ではありません。誰かの4年落ちのノートパソコンの予告編です。
失敗の出力は、ローカルで実行したときと同じ形で返ってきます。どのスペックか、どのアサーションか、インターフェースが実際に何を表示していたか。修正して、また送る。このループは退屈で、退屈であることこそが要点です。
ユニットテストが体よく見逃すもの
このスイートが見つける最良のバグは、決してユニットテストがカバーする層にはありません。それらは継ぎ目に潜んでいます。受信トレイから開いたスレッドが、間違ったメールボックスの返信本文を表示する。移動したメッセージがサーバーからは消えたのに、リストからは消えていない。アーカイブ操作自体は成功したのに、違う行のアイコンが再描画される。そのどれもが、3つのサブシステムがそれぞれ個別には正しく振る舞いながら、全体としては間違っているという状態です。それを捕まえられる唯一のテストは、ユーザーがすることをそのまま行うテストです。
だからこそ、スペックは関数名ではなく、ユーザーの文章として書かれています("marks a selected row as read and repaints it")。1つが失敗したとき、そのレポートは人が起票するバグ報告のように読めます。
スイートを自分で実行する
MailVault はオープンソースであり、スイートはすべてモックサーバーに対してのみ実行されます。アカウントも、認証情報も、設定も一切不要です。Node 18 以降と Rust ツールチェーンがインストールされていれば:
git clone https://github.com/GraphicMeat/mail-vault-app
cd mail-vault-app
npm install
cargo install tauri-webdriver-automation
npm run test:e2e
cargo install は tauri-wdを提供します。これは、スイートがアプリを操作するために起動する WebDriver ブリッジです。最後のコマンドが残りをすべて行います。テストモードでフロントエンドをビルドし、Rust バックエンドを webdriver 機能付きでコンパイルし、モック IMAP サーバーを起動して、全スペックを通してアプリを操作します。最初の実行はほとんどの時間を Rust コンパイラの中で過ごします。その後は、 npm run test:e2e:ui と npm run test:e2e:connected がそのビルドを再利用し、それぞれのスイートを直接実行します。
実行中、アプリのウィンドウは開いては自らクリックし、閉じる、を延々と繰り返します。ロボットがメールを読んでいる様子をどう感じるかにもよりますが、不気味でもあり、まさにその通りのことをしているとも言えます。
まだ解決できていないこと
誠実さはマーケティングより安上がりなので、正直に言います。モックサーバーが話すのは私たちが実装した IMAP であって、Gmail や Outlook が即興で使うあらゆる方言ではありません。実際のプロバイダに対する OAuth サインインは、いまも人間の手で検証しています。ビジュアルリグレッションとバックアップのスイートは、まだ手動で実行しており、送信のたびには走りません。そして mini は一度に1つのスイートしか、順番にしか実行しません。16ギガバイトのメモリは予算であり、不安定な2回の実行より、信頼できる1回の実行のほうがましだと考えています。この3つはすべてリストに載っており、この順番で取り組みます。
その間も、機能はゆっくりとしたやり方でしか届きません。書かれ、送られ、退屈することのない小さなコンピュータにクリックされ尽くし、何も見つからなくなって初めて出荷されます。あなたのメールには、少なくともそれだけの儀式を受ける価値があります。
あなたのメールは、ローカルにアーカイブされ、宣伝されるより厳しくテストされているアプリに扱われます。 macOS と Linux 向けに無料でオープンソースです。
MailVault にアクセスしてください →