Write Tests for User Locking and Unlocking and Finish the Devise Epic
Channel: Stateless Code
Date: 03/12/2022

As we near the end of the Devise user authentication epic for our Ruby on Rails 7 application, there is one more set of functionality that we want to test. We configured our application to lock an account after 10 unsuccessful login attempts. This helps prevent a brute force attack on a user with a list of compromised passwords. Ideally nobody should reuse passwords anywhere, but we know real life users aren't always responsible when it comes to managing their own security.

In order to ensure that things are working as expected, we want to test that the user gets a warning for the last attempt with a bad password, the account locks on the final attempt, and once the account is locked, you cannot login even with the correct credentials. 

We configured Devise to unlock with an unlock token or after an hour of time passes. The unlock token is a digest, very similar to the reset password token that we tested earlier. 

But how do we test the time-related unlock? We don't want to pause our tests for an hour of real life time to wait for the unlock condition to be met. Fortunately Rails provides a ActiveSupport::Testing::TimeHelpers module to solve for this issue. We can use the travel method to advance forward in time to a point when a sufficient amount of time has elapsed.

After implementing all the test scenarios, we review the entire epic and ensure adequate commenting. Ideally we should be doing this on every commit, but we neglected this a bit, so we're going to take care of it now before we merge back into the main branch.

This video covers:
00:00:12 Introduction
00:02:05 Demonstrate the functionality to be tested
00:09:46 Create the test class and stub out the tests
00:12:15 Warns user with 1 failed attempt left
00:13:25 Locks after failed attempts reached
00:14:18 Refactor out locking behavior into private method
00:16:03 User can unlock account via emailed token
00:27:38 Use the travel method to test user account unlocks after specified time elapses
00:30:11 User cannot unlock with an invalid token, but can resend it and unlock
00:40:25 Restore assertions about emails using sleep
00:41:27 User can resend unlock instructions and unlock
00:42:47 Refactor resend token behavior into private methods
00:45:43 Errors out if you try to resend unlock instructions to a bad email
00:49:07 Fix RuboCop offenses and refactor out smaller private method to reduce method length and Assignment Branch Condition issue, commit new test class.
00:53:09 Review epic and improve commenting on the project, remove documentation comment exclusions from rubocop.yml, shorten sleep from 1 to 0.1
00:56:43 Commit changes for commenting, push to remote, create and merge pull request, close issue, update project

#ruby #rails7 #rails #rubyonrails #rubygems #codecast #screencast #github #opensource #minitest #TDD #agile #NerdDice #DnD #roleplaying #softwaredevelopment #learntocode #tailwind #postgresql #rubocop #devise #turbo #controllers #views #selenium #capybara #systemtest

See other related StatelessCode videos:
- Write and Debug Happy Path System Tests for Devise Reset Password https://youtu.be/yz4DJ2Rtsh0

Resources that we relied upon for this solution:
- Rails testing time helpers https://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html

This video is CC0 - No rights reserved. (YouTube doesn't allow this option when publishing.) All code is released under the UNLICENSE.  Stateless Code denies the concept of "intellectual property". Copying is not stealing.