BOM付きのCSVダウンロード系の機能の検証をRequest specでresponse bodyのBOM付きCSVを検証する時に若干ハマったのでやり方をメモ🗒
BOM付きのCSVを検証する時の注意点
当たり前といえば当たり前ですが、encoding: 'bom|utf-8'
を指定しないとパース時にエラー(Illegal quoting in line 1. CSV::MalformedCSVError
のような)になるので注意が必要です。
さらにパースできても以下のようにBOMが入っているのでkeyのマッチができなくなります。※ rows['column']
が一見keyが一致しているように見えてもBOMによりnilが返却されます。
実運用ではエクセル等で文字化けせずに利用できて便利ですが、テストコードでBOM付きCSVを扱うのは大分大変です。
いい感じに検証する
上記の通りBOM付きCSVをそのまま扱うのは厳しいのでテストコードではBOMを削除して扱います。
response.body.delete("\uFEFF")
でBOMを削除し、削除した文字列をそのままCSV.parse
でパースして中身を検証しています。
describe 'GET /records.csv' do before { get records_path(format: :csv) } it '成功すること' do expect(response).to have_http_status(:ok) end it '適切なCSVが出力されること' do rows = CSV.parse(response.body.delete("\uFEFF"), headers: true).map(&:to_h) expect(rows.length).to eq 2 expect(rows.last)).to eq( { 'column1' => 'value1', 'column2' => 'value2', } ) end end
※以下の通りBOMは容認されているが推奨されているものではんく削除によるリスクはほぼ無いものと判断しました。
UTF-8は文字コードとしてASCIIを前提としたプログラムでもおよそ支障なく動作するように設計されているが、BOMによって正常に処理できなくなる場合がある。Unicodeの規格において、UTF-8においてBOMは容認されるが、必須でも勧められるものでもないとされている[5]。また、データベースやメモリにロードするデータなど、内部的なデータ形式では、プログラムの性能や効率の観点から普通BOMは用いられない。 バイト順マーク - Wikipedia