Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I write system tests with clearance? #1022

Open
avk opened this issue May 16, 2024 · 4 comments
Open

How do I write system tests with clearance? #1022

avk opened this issue May 16, 2024 · 4 comments

Comments

@avk
Copy link

avk commented May 16, 2024

I'm struggling with adding clearance to my system tests.

class PiecesTest < ApplicationSystemTestCase
  setup do
    @writer = writers(:one)
    @piece = pieces(:one)
    @fields = {
      draft: t("activerecord.attributes.piece.draft"),
      prose: t("activerecord.attributes.piece.prose"),
      title: t("activerecord.attributes.piece.title"),
      word_count: t("activerecord.attributes.piece.word_count_suffix"),
    }
  end

  test "should add a new prose piece" do
    visit pieces_url(as: @writer)
    click_on t("pieces.actions.new"), match: :first

    check @fields[:prose]
    fill_in @fields[:word_count], with: 5000
    fill_in @fields[:title], with: "Prose Piece"
    fill_in @fields[:draft], with: 1
    click_on t("pieces.actions.submit")

    assert_text t("pieces.actions.created")
  end
end

The backdoor middleware, will only work for the visit call (the first line of the test). It doesn't work with redirects, like the one generated by the click in the second line of the test.

The controller test helpers are also not available if I require "clearance/test_unit".

What else can I try to get this to work?

@avk
Copy link
Author

avk commented May 18, 2024

This feels hacky, but here's the first approach I got working across multiple system tests and navigation even within a test:

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  driven_by :selenium, using: :headless_firefox, screen_size: [1400, 1400]

  def sign_in_as(writer)
    # why? ensure cookies can be set on first navigation
    visit root_url if page.driver.browser.current_url == "about:blank"

    # Selenium driver interface to auth cookie borrowed from 
    # https://github.com/nruth/show_me_the_cookies/blob/master/lib/show_me_the_cookies/adapters/selenium.rb
    page.driver.browser.manage.add_cookie(
      # How Clearance keeps track of authenticated users
      name: Clearance.configuration.cookie_name,
      value: writer.remember_token
    )
  end

  def sign_out
    # Selenium driver interface to auth cookie borrowed from 
    # https://github.com/nruth/show_me_the_cookies/blob/master/lib/show_me_the_cookies/adapters/selenium.rb
    page.driver.browser.manage.delete_cookie(
      # How Clearance keeps track of authenticated users
      Clearance.configuration.cookie_name
    )
  end
end

And if I call sign_in_as in setup or in a test, the authentication will persist for the whole test.

class PiecesTest < ApplicationSystemTestCase
  setup do
    @writer = writers(:one)
    sign_in_as @writer
    @fields = {
      draft: t("activerecord.attributes.piece.draft"),
      prose: t("activerecord.attributes.piece.prose"),
      title: t("activerecord.attributes.piece.title"),
      word_count: t("activerecord.attributes.piece.word_count_suffix"),
    }
  end

  test "should add a new prose piece" do
    visit pieces_url # redirects if not signed in
    click_on t("pieces.actions.new"), match: :first # navigates to new page

    check @fields[:prose]
    fill_in @fields[:word_count], with: 1000
    fill_in @fields[:title], with: "Prose Piece"
    fill_in @fields[:draft], with: 1
    click_on t("pieces.actions.submit") # navigates to new page

    assert_text t("pieces.actions.created")
  end
end

The above works with secure cookies, but doesn't work with signed cookies.

Clearance.configure do |config|
  # ...
  config.signed_cookie = false # breaks system tests
  # ...
end

This approach was considerably faster than navigating to sign_in_path and filling out the session form, and as stated originally, more flexible than the backdoor when navigating across pages without explicit visit calls.

I'm very open to other approaches.

@avk
Copy link
Author

avk commented Jul 18, 2024

I could still use input on this. I tried to extend the above example to work with the rack-test driver and had no luck. I could set the cookie, but Clearance would seemingly not be logged in during those system tests.

@louis-antonopoulos
Copy link
Contributor

@avk I ran into something similar with Clearance in my system tests, and I wonder if what you experienced was related to using secure cookies?

As mentioned in Issue 961: Generated specs don't work with secure cookies, the following workaround allows me to
visit some_path(as: some_user)
and then take an action like clicking on a New or Save button that redirects or posts:

In config/initializers/clearance.rb:

config.secure_cookie = true unless Rails.env.test?

With this configuration, I did not have to define any custom methods in ApplicationSystemTestCase (like you included above) to get my system tests to work as expected.

@avk
Copy link
Author

avk commented Feb 5, 2025

I changed all my visit calls to use as: for the backdoor and tried config.secure_cookie = false, but I get a whole host of failures that don't appear when I use my sign_in_as method in ApplicationSystemTestCase above.

Some failures seem tied to JavaScript execution. Perhaps something else is at play, but the only symptom I see is how I seem to authenticate my system tests with Clearance :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants