0

I tried this solution https://gist.github.com/alexeyrazuvaev/98448c9935352fac5ee96e139bc3bd72 and it doesn't work with my test. Tried reproducing it in the browser and it works as expected. I can't figure out what's the problem with my test.

This is the example:

scenario 'they see their name and message in the chat box', js: true do
  find('textarea#message_content').send_keys(:enter)
  is_expected.to have_selector('p', text: /^#{current_user.name}|foobar$/)
end

Other information:

cable.yml

redis: &default
  adapter: redis
  url: redis://localhost:6379/1

production: *default
development: *default
test: *default

spec/support/capybara.rb

Capybara.javascript_driver = :webkit
Capybara.server = :puma

Capybara::Webkit.configure do |config|
  config.allow_url("https://code.jquery.com/jquery-3.3.1.min.js")
end

test.log

# ...
Started GET "/cable" for 127.0.0.1 at 2018-01-30 11:21:16 +0800
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2018-01-30 11:21:16 +0800
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Registered connection (Z2lkOi8vY2hhdHRlci9Vc2VyLzE)
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversation_channel_1
Finished "/cable/" [WebSocket] for 127.0.0.1 at 2018-01-30 11:21:18 +0800
ConversationChannel stopped streaming from conversation_channel_1
# ...

server log when testing it to browser

# ...
Started GET "/cable" for 127.0.0.1 at 2018-01-29 09:02:02 +0800
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2018-01-29 09:02:02 +0800
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
  User Load (1.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Registered connection (Z2lkOi8vY2hhdHRlci9Vc2VyLzE)
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversation_channel_11
ConversationChannel#send_message({"content"=>"foobar\n", "conversation_id"=>"11"})
   (0.2ms)  BEGIN
  Conversation Load (0.3ms)  SELECT  "conversations".* FROM "conversations" WHERE "conversations"."id" = $1 LIMIT $2  [["id", 11], ["LIMIT", 1]]
   (0.6ms)  SELECT "users"."id" FROM "users" INNER JOIN "user_conversations" ON "users"."id" = "user_conversations"."user_id" WHERE "user_conversations"."conversation_id" = $1  [["conversation_id", 11]]
  SQL (12.5ms)  INSERT INTO "messages" ("content", "user_id", "conversation_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["content", "foobar\n"], ["user_id", 1], ["conversation_id", 11], ["created_at", "2018-01-29 01:02:18.272060"], ["updated_at", "2018-01-29 01:02:18.272060"]]
   (12.4ms)  COMMIT
  Rendered messages/_message.html.erb (0.8ms)
[ActionCable] Broadcasting to conversation_channel_11: {:message=>"<p>John Doe: foobar\n</p>\n"}
ConversationChannel transmitting {"message"=>"<p>John Doe: foobar\n</p>\n"} (via streamed from conversation_channel_11)
gbertl
  • 321
  • 2
  • 16
  • 1
    Assuming you've set `Capybara.server` to puma, are running actioncable in process (async adapter), and have allowed actioncable to make connections from the ip/domain you're tests are running on it should work. Add your Capybara and actioncable configs to your question. Also check your test.log for any errors related to actioncable connections. – Thomas Walpole Jan 28 '18 at 18:54
  • @ThomasWalpole check the updated question – gbertl Jan 29 '18 at 01:15
  • Try changing the cable.yml to use the `async` adapter in test mode (the default rails config) rather than `redis` – Thomas Walpole Jan 29 '18 at 01:42
  • Also, can try running it with `selenium` rather than `capybara-webkit` - I thought the Qt `capybara-webkit` supported didn't really work with WebSockets (although I could be wrong about that, and the logs seem to show it is at least doing the connection). The other thing to check is what output `puma` produces when you run your tests. Does it show it's running in 'single mode' or 'clustered mode'? Also, I'm assuming `is_expected` is equivalent to `expect(page)` ? – Thomas Walpole Jan 29 '18 at 01:44
  • @ThomasWalpole you're right puma is in single mode, and I set `subject` to page so `is_expected` is equivalent to `expect(page)`. – gbertl Jan 29 '18 at 02:30
  • Ok - it should be single mode (but with multiple threads - clustered mode runs in multiple processes which gets in the way of a lot of stuff) so I would guess switching to the `async` adapter in test mode should fix things for you. – Thomas Walpole Jan 29 '18 at 02:32
  • One other thing it could be is not having `Capybara.default_max_wait_time` set long enough for the actioncable action to complete. Try setting it 10 or 15 just to rule that out. – Thomas Walpole Jan 29 '18 at 02:38
  • @ThomasWalpole tried using selenium, and I got this error `uninitialized constant Selenium::WebDriver::Remote::W3CCapabilities` might be from selenium-webriver gem. – gbertl Jan 29 '18 at 04:19
  • tried using `async` as well and nothing changed. – gbertl Jan 29 '18 at 04:21
  • As far as the `unitialized constant`, you're either not using the latest Capybara, or you've registered your own :selenium driver and specified the capabilities incorrectly. Did the log output change when using `async`? and did you try increasing the max wait time? – Thomas Walpole Jan 29 '18 at 04:25
  • The example above is passing now after updating capybara to newest version. And using selenium instead of webkit. However my other test `scenario 'adds to user messages', js: true do expect { find('#message_content').send_keys(:enter) }.to change(current_user.messages, :count).by(1) end` doesn't work. – gbertl Jan 29 '18 at 08:19
  • Added an answer, and answered your new issue in the question you opened for it – Thomas Walpole Jan 29 '18 at 15:32

1 Answers1

0

Since this works for you with the selenium driver instead of capybara-webkit there is one of two possibilities.

  1. capybara-webkit doesn't work correctly with websockets. This would be true if you compile it with Qt 4.x, however I believe it should work when built with with Qt 5.x - ActionCable not connecting during capybara-webkit feature spec - and the logs appear to show that is it at least connecting.

  2. You are using ES6+ features in the JS on your page. The QtWebkit used by capybara-webkit is pretty outdated and is basically equivalent to a 6-7 year old version of Safari which means it doesn't support ES6+. Therefore if you've used any ES6+ methods/features in your code without polyfilling and/or transpiling capybara-webkit won't run the JS. Since actioncable does appear to be connecting in the logs it's running at least some of your JS, so enabling 'raise_javascript_errors- https://github.com/thoughtbot/capybara-webkit#configuration - in yourcapybara-webkit` configuration will probably show an error about some method you're using in your key press handler not being supported.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • Thanks for answering. Just add for reference, it doesn't matter if you use redis or async in the test, tried using both and have the same results, I don't know for other complex tests. – gbertl Jan 30 '18 at 03:56