Authentication Spec (Fundamentals of TDD)
Published: 2022-02-17 20:16:07

## Test Driven Development
Test Driven Development, or TDD, is a process of development where the developer first creates test cases for the software, meaning what the developer wants the software to do, and then developing this software by repeatedly testing the software against the predetermined test cases. In most cases, developers do not use TDD; most developers create the software first and then test their software. 

**Inspiration**
TDD can be a very beneficial way of developing because the developer must first write very explicitly what he or she wants the computer to do and then simply follow the error messages to develop the software. In a way, it is like the developer first tells the computer what he or she wants it to do, then the computer tells the developer exactly the steps to developing that software. It can definitely be a nice guide if you do not know _exactly_ the steps you must complete  in order to develop something. 

## Authentication Spec
For my Phase 4 project at Flatiron I have to build a webpage with a React frontend and a Rails backend; the page must feature user authentication using cookies and sessions. Below I created an authentication spec in order to develop the basic login of the webpage. 

**Capybara**
First I installed the [capybara](https://github.com/teamcapybara/capybara) gem and added it to my Gemfile. Next you want to add `require 'capybara/rails'` below `require 'rspec/rails'` in your `rails_helper.sb` file. Next, you have to add `capybara/rspec` in your `spec_helper.sb` file. 

**authentication_spec.rb**
The next step is to create a file in `your-app/spec/features` called `authentication_spec.rb`. Let's take a look inside this file:

```
require 'rails_helper'

describe "the signin process", type: :feature do
   let!(:user) do
      User.create(username: 'username', password: 'password')
    end
  
    it "signs me in" do
      visit '/'
      within("#log_in_form") do
        fill_in 'username', with: user.username
        fill_in 'Password', with: user.password
      end
      click_button 'Sign in'
      expect(page).to have_content 'Welcome'
    end
  end
```

Woah! This is a lot to take in so let's break it down:

`describe "the signin process", type: :feature do`

In the line of code above we are describing what we want to test. In this case we are trying to make authentication work, so we are going to test the sign-in process of our application. 

`let!(:user) do
      User.create(username: 'username', password: 'password')
    end`

Here we use the bang operator (!) on let in order to create a  user instance. 

`it "signs me in" do
      visit '/'
      within("#log_in_form") do
        fill_in 'username', with: user.username
        fill_in 'Password', with: user.password
      end`

In the code block above we are telling the computer explicitly what we want the test to do. The test is going to visit our root directory and within that root directory it is going to look for an HTML element with an ID of `'log_in_form'`. Within this form it is going to fill in the part of the form called 'username' with our username of our user instance we created above, along with the password. Finally it is going to:
`click_button 'Sign In'`

The last part of our code is very important: it is what the computer should expect to see in order to know that the test has passed! In our case we should see some kind of greeting when we are logged in. We can express this to the computer by saying: 
`expect(page).to have_content 'Welcome'`

**Putting it all together**
Ok so now we have our test in place - let's run it! Go to the console and type `bundle exec run your-app/spec/features/authentication_spec.rb`. Your test should be failing! Not only should it be failing but you should also get an error message saying what specifically failed. Now you want to repeatedly run this test, debugging each and every error message until the test passes. Then you will know that your software is doing exactly as you want it to and you never even had to leave VSCode!