RSpec の spec type を独自フォルダ配下の spec にも自動で付与したい

f:id:shutooike:20210420184634p:plain

おはようございます!

最近 DMM Books の70%OFF祭りで読みたかった技術書を50冊 *1 ほど買い込んだ @shutooike です!

前回 と同様に、今回も整備中に見つけた RSpec 小ネタを共有します。

前提条件

rspec-rails: 3.9.0

spec type の自動付与とは?

# spec/rails_helper.rb

RSpec.configure do |config|
  config.infer_spec_type_from_file_location!
end

rails_helper.rb 内で上のようにすると

spec/models 配下の spec には type: :model というメタデータがつきます。これを今回は spec type の自動付与と呼びます。

この自動付与が行われるのは以下の場合のみで spec/ に掘った独自ディレクトリには当たり前ですが付与されません。

ディレクトリ タイプ
spec/controllers :controller
spec/helpers :helper
spec/jobs :job
spec/mailer :mailer
spec/models :model
spec/request, spec/integration, spec/api :request
spec/routing :routing
spec/view :views
spec/feature :feature
spec/system :system

やりたいこと

うちでは spec/lib/ という独自ディレクトリに lib/ の spec を書いていて、配下の spec に type: lib を付与する必要が出てきました。

解決策

# spec/rails_helper.rb

RSpec::Rails::DIRECTORY_MAPPINGS[:lib] = %w(spec lib) # <- この行を追加

RSpec.configure do |config|
.
.

解説

先ほど紹介した config.infer_spec_type_from_file_location!実装 を見ると

def infer_spec_type_from_file_location!
  DIRECTORY_MAPPINGS.each do |type, dir_parts|
    escaped_path = Regexp.compile(dir_parts.join('[\\\/]') + '[\\\/]')
    define_derived_metadata(:file_path => escaped_path) do |metadata|
      metadata[:type] ||= type
    end
  end
end

ほうほう、DIRECTORY_MAPPINGS というハッシュを回して type を付与しているっぽいですね。

DIRECTORY_MAPPINGS定義 を見にいきましょう。

DIRECTORY_MAPPINGS = {
  :controller => %w[spec controllers],
  :helper     => %w[spec helpers],
  :job        => %w[spec jobs],
  :mailer     => %w[spec mailers],
  :model      => %w[spec models],
  :request    => %w[spec (requests|integration|api)],
  :routing    => %w[spec routing],
  :view       => %w[spec views],
  :feature    => %w[spec features],
  :system     => %w[spec system]
}

ビンゴ!しかも freeze されていないので後から追加可能です。

また DIRECTORY_MAPPINGS は 2021/04/25 現在の main ブランチでも定義されてたので当分はバージョンアップに怯える必要もなさそうです。

おわりに

Rubymine のコードジャンプがあればソースリーディングが簡単にできていいですね〜

弊社では全ての分野のエンジニアを絶賛大募集中です!ご興味あればぜひ下記リンクからお願いします!

ingage.co.jp

ではまた!

*1:15万(総額) - 10万(クーポン) = 5万(支払い金額) という崩壊っぷりでした。