Open machida opened 4 months ago
products
ページの方はVueからReactに置き換え済み@komagata @machida お疲れ様です。 本イシューでは既存のVueをRailsのViewComponentへ置き換えをしています。 ViewCompoentのテストの実装で上手くいかない点があり、アドバイスをいただけますでしょうか 🙇 (※2024/9/30 18:50 エラー内容、エラーが発生するパターンを少し修正しました)
ViewComponentのテストでActiveDecoratorメソッドがundefined method
エラーとなる。
(以下、ViewComponentのテスト = コンポーネントテスト
、ActiveDecoratorメソッド = デコレーターメソッド
と記載します)
例えば、ViewComponentのhtml
ファイルでuser.icon_title
を呼び出す部分で以下のようなエラーが発生する。
(エラーの発生するテストコードはまだPRには含めていません)
エラーが発生するのはコンポーネントテストから呼び出した時のみで、テスト以外(ブラウザから呼び出す)はエラーは発生しない。
❯ rails test test/components/product/product_component_test.rb
Running via Spring preloader in process 11715
Run options: --seed 21297
# Running:
....E
Error:
Products::ProductComponentTest#test_render_comments_count_when_there_are_comments:
NoMethodError: undefined method `icon_title' for #<User id: ...
...
{中略}
...
app/components/products/product_component.html.slim:71:in `block in call'
app/components/products/product_component.html.slim:69:in `call'
test/components/product/product_component_test.rb:67:in `test_render_comments_count_when_there_are_comments'
rails test test/components/product/product_component_test.rb:64
active_decorator
gemによって導入されるapp/decorators/user_decorator.rb
などのファイルで定義されているuser = user.extend(UserDecorator)
とすることでインスタンスからデコレーメソッドの呼び出せるproduct.user = product.user.extend(UserDecorator)
とすることでデコレータメソッドを呼び出せる以下のように、コンポーネントテストでデコレーターを適用したuser
でproduct
にcomment
を作成した後、html側でcomment
からuser
を取得してデコレーターメソッドを呼び出そうとすると、undefined method
となる。
コンポーネントテスト ※PRには未実装
# test/components/product/product_component_test.rb
def test_render_comments_count_when_there_are_comments
commented_user = users(:komagata).extend(UserDecorator)
unassigned_product = decorate_product_user(products(:product6))
unassigned_product.comments.create!(user: commented_user, description: 'コメントを追加')
render_inline(Products::ProductComponent.new(
product: unassigned_product,
is_mentor: @is_mentor,
current_user_id: @current_user_id
))
assert_selector '.a-meta', text: 'コメント(2)'
assert_selector 'img.a-user-icon[title=?]', commented_user.icon_title
end
ViewComponentのhtmlファイル
ここのuser.icon_title
がundefined method
エラーとなる
対応方法を検討しましたのでご助言お願いできますでしょうか。
モデルとビューをスリムにするためにロジックを記述する場所
という役割が被っているという認識です。ViewComponentではデコレーターメソッドは使わずにコンポーネントのロジック部分に代わりにそのロジックを記述すべきなのでしょうか?extend(HogeDecorator)
でデコレーターを適用しないでもデコレーターメソッドが利用できます。コンポーネントテストでも同様のことが可能なのであればその方法をご教授いただけますでしょうか?以上、お手数ですがご回答をお願いいたします。
@Shrimprin
- ViewComponentのロジック部分とActiveDecoratorはモデルとビューをスリムにするためにロジックを記述する場所という役割が被っているという認識です。ViewComponentではデコレーターメソッドは使わずにコンポーネントのロジック部分に代わりにそのロジックを記述すべきなのでしょうか?
- システムテストでは明示的にextend(HogeDecorator)でデコレーターを適用しないでもデコレーターメソッドが利用できます。コンポーネントテストでも同様のことが可能なのであればその方法をご教授いただけますでしょうか?
2でお願いします。もうちょっとだけ調べてみてください〜
@komagata
お疲れ様です!
Active Recordのafter_find
コールバックを使ってデコレーターを適用するヘルパーを作成して、問題を対処できるようにしました。
以下のような実装方針で良いかご助言お願いできますでしょうか。
デコレーターを適用するヘルパー https://github.com/fjordllc/bootcamp/blob/51a6fe0f6d6eb43d3c9b5b775c0912ffb44a022e/test/supports/decorator_helper.rb#L3-L7
コンポーネントテストでの使用方法
コンポーネントテストのsetup
メソッドで以下のようにして呼び出します。
require 'test_helper'
require 'supports/decorator_helper' # ヘルパーをrequireする
class Products::ProductsComponentTest < ViewComponent::TestCase def setup DecoratorHelper.auto_decorate(User) # デコレーターを適用したいモデルを引数で渡す
end
end
これにより`User`レコードを読み込むたびにデコレーターが適用され、テスト内で毎回`extend(UserDecorator)`しなくて済みます。
### 参考
- [Railsガイド after_initializeとafter_find](https://railsguides.jp/active_record_callbacks.html#after-initialize%E3%81%A8after-find)
いいと思います。ただ下記に似たコードがあるので何かしら共通化できるといいかもですね。
bootcamp/test/active_decorator_test_case.rb at main · fjordllc/bootcamp
@komagata ありがとうございます。 共通化も含めてPRを作成していきます。
メンターでログインしたときにダッシュボードに表示されるこれが今はVueで実装されているので、Railsのviewに移行する。