スナップショットテストの可読性改善:`pretty`ヘルパーによるマージコンフリクト軽減
VitestのインラインスナップショットでCSSの先頭と末尾に " が現れる問題を解消するため、pretty ヘルパー関数が導入されました。これにより、マージコンフリクト発生時の解消作業が簡略化されます。
背景
Vitestのインラインスナップショットは、期待値をバックティック内のダブルクォートで囲んだ形式で記録します。この仕様により、CSSを直接スナップショットに入れると先頭行と末尾行に " が付与され、マージコンフリクトの解消時に余計な考慮が必要になっていました。
具体的には、変更前のスナップショットは以下のような形式でした:
expect(result.css.trim()).toMatchInlineSnapshot(`
"@layer utilities {
.foo {
color: #000;
}
}"
`)
CSSの先頭が "@layer 、末尾が }" のように " と結合された状態になるため、コンフリクトマーカーの解消時にこの引用符を意識しながら編集する必要がありました。PR著者はこの問題に「すでに十数回遭遇した」と説明しています。
また、空文字列を期待するテストで .toMatchInlineSnapshot() を使っていた箇所も問題でした。スナップショットの更新が「簡単すぎる」ため、バグによって何かが生成されても気づきにくいリスクがあります。
技術的な変更
packages/tailwindcss/src/test-utils/run.ts に pretty ヘルパー関数が追加され、テストヘルパー全体の出力形式が統一されました。
変更前:
export async function compileCss(...) {
let { build } = await compile(css, options)
return optimize(build(candidates)).code.trim()
}
export async function run(candidates: string[]) {
let { build } = await compile('@tailwind utilities;')
return optimize(build(candidates)).code.trim()
}
export function optimizeCss(input: string) {
return optimize(input).code
}
変更後:
export async function compileCss(...) {
let { build } = await compile(css, options)
return pretty(optimize(build(candidates)).code)
}
export async function run(candidates: string[]) {
let { build } = await compile('@tailwind utilities;')
return pretty(optimize(build(candidates)).code)
}
export function optimizeCss(input: string) {
return pretty(optimize(input).code)
}
export function pretty(input: string) {
input = input.trim()
if (input === '') return ''
return `\n${input}\n`
}
pretty 関数はシンプルな実装です。トリム後の入力が空文字列なら '' を返し、そうでなければ入力を \n で前後に挟みます。これにより、スナップショットの外側の " からCSSが分離されます。
この変更によって、スナップショットの見た目は以下のように変わります:
expect(pretty(result.css)).toMatchInlineSnapshot(`
"
@layer utilities {
.foo {
color: #000;
}
}
"
`)
CSSの先頭行が " と結合されなくなるため、コンフリクト解消時にCSS行だけを見ればよくなります。また、空出力の期待には .toMatchInlineSnapshot() ではなく明示的な .toEqual('') を使うよう変更され、意図しない出力を見逃しにくくなっています。
設計判断
css タグドテンプレートリテラルを使うアプローチ も検討されましたが、採用されませんでした。
PR本文では、String.raw として実装した css タグを使いスナップショットをCSSとして直接記述する案が言及されています。エディタのシンタックスハイライトやPrettierによるフォーマットも活用できる点で魅力的ですが、2つの問題がありました。1つ目はPrettierによるフォーマットが入出力の不一致を生む可能性があること、2つ目はVitestがバックスラッシュをダブルエスケープするため \[color:red\] のようなセレクタでスナップショットが壊れることです。カスタムスナップショット環境を使えば技術的には実現可能ですが、間接層が増え、テストの信頼性に微妙な影響を与える可能性があるとして見送られています。
結果として、pretty による \n の挿入という最小限の変更が選ばれました。既存のテストヘルパー(compileCss・run・optimizeCss)の内部で pretty を呼ぶことでほとんどのテストが自動的に新形式に移行でき、各テストファイルへの変更を最小化しています。
まとめ
pretty ヘルパーの導入は、テスト出力のフォーマットをわずかに変えるだけでマージコンフリクトの解消コストを下げ、空出力テストの安全性も高める実用的な改善です。テストインフラを整備することで、コードベースの長期的なメンテナンス性が向上します。