1

I'm using Devise + Confirmable for user authentication and Minitest + Capybara + fixtures for testing. I can make working logged in tests for users as long as I included some form of login (either with the helper login_as(@user) or going to the login page with Capybara) and the line@user.confirm before running.

How can I confirm users in the fixture itself though so I don't have to include this line every time.

Right now I have:

confirmed_at: Time.now

in the yml, but it doesn't seem to make a difference.

Here is a working sample test, if it's useful for illustration:

def setup
    @user = users(:user)
  end

   test 'user should be redirected to profile edit on first login' do
     @user.confirm
     visit(new_user_session_path)
     fill_in('user_email', :with => @user.email)
     fill_in('user_password', :with => 'foobar')
     click_button('Log in')
     assert_current_path(edit_user_registration_path)
   end

and the user fixture:

user:
  email: test1@example.com
  confirmed_at: Time.now
  encrypted_password: <%= Devise::Encryptor.digest(User, 'foobar') %>
  sign_in_count: 0
  • So the user was created, saved and not yet confirmed? You want to edited that database field manually? – Fabrizio Bertoglio Mar 14 '17 at 07:13
  • As far as I know the fixtures are not actually saved to the DB. When I look at the users in the development DB neither of the two fixture users are there. – oneWorkingHeadphone Mar 14 '17 at 09:36
  • Hello, I updated my answer. The solution of the problem is found hear. You need to configure it as in the guide and call the method user.confirm! inside the module ControllerMacros method def login_user https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)#controller-specs – Fabrizio Bertoglio Apr 21 '17 at 08:36
  • @FabrizioBertoglio the guide moved at https://github.com/heartcombo/devise/wiki/How-To:-Test-controllers-with-Rails-(and-RSpec) but the `Date.today` stated there doesn't work (_non funziona_ :/)! Here is the solution: https://stackoverflow.com/a/75052159/824806 – Backo Mar 06 '23 at 23:13

2 Answers2

2

I updated my answer. The solution of the problem is found here. You need to configure it as in the guide and call the method user.confirm! inside the module ControllerMacros method def login_user

https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)#controller-specs

Open source github page of a complete Devise Rspec Project including testing

https://github.com/RailsApps/rails-devise/blob/master/spec/features/users/sign_in_spec.rb


you are trying to set

User.confirmed_at = Time.now

but confirmed_at has datetime datatype at least in my postegresql db, so this may depend on the db you are using.

confirmed_at: datetime

So this is the Time.now format

pry(main)> Time.now
=> 2017-03-14 11:14:06 +0100

While this is is the User.confirmed_at format

user.confirmed_at
=> Sun, 05 Mar 2017 15:05:03 UTC +00:00

So you should use a compatible format/variable, try to search the DateTime class for a compatible format that includes the UTC as DateTime.now returns:

[40] pry(main)> DateTime.now
=> Tue, 14 Mar 2017 11:19:25 +0100

DateTime has a utc() method. If I run this it is almost what is needed.

DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc

DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc
=> 2005-02-21 16:11:12 UTC

Check the DateTime api and if needed you can check the utc() method on github

DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24))     # => Mon, 21 Feb 2005 10:11:12 -0600
DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC


# File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 168
def utc
  utc = new_offset(0)

  Time.utc(
    utc.year, utc.month, utc.day,
    utc.hour, utc.min, utc.sec + utc.sec_fraction
  )
end

http://api.rubyonrails.org/classes/DateTime.html#method-i-utc

Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94
Fabrizio Bertoglio
  • 5,890
  • 4
  • 16
  • 57
  • I think this is on the right track, but dateTime.now didn't work for me. The DB is the default SQLite setup. After I read this I found [SQLite should take date('now')](https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users) in the Devise docs. I've tried this syntax, but no luck. – oneWorkingHeadphone Mar 14 '17 at 10:44
  • @oneWorkingHeadphone There is a method to confirm devise user `.skipconfirmation!`. When you create the user with `user = User.new` you call `user.skip_confirmation!` and then you save – Fabrizio Bertoglio Mar 14 '17 at 11:04
  • This wouldn't pull the user data out of the fixture though would it? – oneWorkingHeadphone Mar 14 '17 at 11:18
  • @oneWorkingHeadphone Sorry. I can not answer you right now. I will find you a solution tomorrow. – Fabrizio Bertoglio Mar 14 '17 at 11:32
  • Thanks for following up on this! The instructions that you added do work, but not for fixtures + Minitest (they are for Rspec + FactoryGirl). In the end I was able to make this work with a version of this Using Minitest + FactoryGirl, but was never successful in making it work with fixtures. If any users stumble on this later, I suggest that you just use FactoryGirl and the method that Fabrizio has linked to. – oneWorkingHeadphone Apr 21 '17 at 12:29
  • Check my answer to see how to use fixtures only. It works for me out of the box in rails 7 within a minitest IntegrationTest. – randmin Jun 13 '23 at 14:31
0

I had a tough time figuring out why the devise test helper method sign_in users(:one) did not work. It was due to the usage of the :confirmable module. I managed to fix the fixtures like so:

# fixtures/users.yml
one: 
  email: "user1@test"
  confirmed_at: <%= Time.current %>

(The OP does not include the ERB tags <%= %>. Also note that in rails 7 you do not need to change the file extension to yml.erb, as the ERB within fixtures is parsed anyway)

randmin
  • 818
  • 8
  • 16