Search code examples
ruby-on-railsrspeccapybararspec-railsmaterialize

Test that a toast fires off in a Capybara feature spec?


I have a Rails app that I've recently refactored standard flash[:success] messages to use a flash[:toast], using http://materializecss.com/dialogs.html

Here's what I'm doing with my flash partial:

<% flash.each do |type, message| %>
  <% if type == "success" %>
    <div class="alert alert-success alert-dismissable" role="alert">
      ...
    </div>
  <% elsif type == "toast" %>
    <script>
      $(function() {
        Materialize.toast('<%= message %>', 3000);
      });
    </script>
  <% else %>
    <div class="alert alert-danger alert-dismissible" role="alert">
      ...
    </div>
  <% end %>
<% end %>

This works and looks awesome, especially on mobile and for complex data pages where I'm sending the user back to the middle of the page, and a standard flash success message on the top of the page would not be visible.

I can easily test if flash[:toast] is not nil in a controller test, but in capybara feature tests, I don't have access to that, and I can't use the standard code that I used to use to test flash[:success] like:

expect(page).to have_content("Your email address has been updated successfully.")
expect(page).to have_css(".alert-success")

Right now I am resorting to just testing that an alert danger is not present, like:

expect(page).to_not have_css(".alert-danger")

This works, but isn't really testing that the toast fired off. Is there any way to check that the javascript fired or that the toast appeared on the page for the 3 seconds?


Solution

  • As long as you're using a JS capable driver (pretty much anything but the default rack-test driver) then

    expect(page).to have_content("The message shown by the toast") 
    

    should find the toast when it displays on the page. If you want to check that it appears and disappears within 3 seconds you could do something like

    expect(page).to have_content("The message shown by the toast") 
    expect(page).not_to have_content("The message shown by the toast", wait: 3)
    

    The first statement should wait for the text to appear and the second will wait up to 3 seconds for it to disappear. If you want to actually verify the text is being shown in the toast container then you could do

    expect(page).to have_css("#toast-container", text: "The message shown") #update css selector to whatever container you are displaying the toast in
    expect(page).not_to have_css("#toast-container", text: "The message shown", wait: 3)