samedi 4 mars 2017

Rspec doesn't find link if it's at the bottom of page, but does if the link is moved to the top

I am following an online tutorial to set up a rails TodoList app with nested resources.

The course includes rspec files to allow me to check my progress as I go through assignments.

I kept getting the below Rspec failure to find a link, even though when I visited the page I could see it there with the correct format. (The entire rspec file is included at the end of this post)

I spent ages looking at my routes etc, but then tried simply moving the link from the end of the page to the top and now the test passes. Why should this be the case?

Rspec failure

  Module #4: Navigation Tests
  rq05
    rq05e
      TodoList page has new TodoItem link with specified URI and method (FAILED - 1)

Failures:

  1) Module #4: Navigation Tests rq05 rq05e TodoList page has new TodoItem link with specified URI and method
     Failure/Error: expect(page).to have_link('New Todo Item', :href => "#{new_todo_list_todo_item_path(tl_id)}")
       expected #has_link?("New Todo Item", {:href=>"/todo_lists/354/todo_items/new"}) to return true, got false
     # ./spec/nested_resources_spec.rb:83:in `block (4 levels) in <top (required)>'
     # ./spec/nested_resources_spec.rb:14:in `block (2 levels) in <top (required)>'

Finished in 47.57 seconds (files took 7.6 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/nested_resources_spec.rb:78 # Module #4: Navigation Tests rq05 rq05e TodoList page has new TodoItem link with specified URI and method

Routes:

                  Prefix Verb   URI Pattern                                             Controller#Action
    todo_list_todo_items GET    /todo_lists/:todo_list_id/todo_items(.:format)          todo_items#index
                         POST   /todo_lists/:todo_list_id/todo_items(.:format)          todo_items#create
 new_todo_list_todo_item GET    /todo_lists/:todo_list_id/todo_items/new(.:format)      todo_items#new
edit_todo_list_todo_item GET    /todo_lists/:todo_list_id/todo_items/:id/edit(.:format) todo_items#edit
     todo_list_todo_item GET    /todo_lists/:todo_list_id/todo_items/:id(.:format)      todo_items#show
                         PATCH  /todo_lists/:todo_list_id/todo_items/:id(.:format)      todo_items#update
                         PUT    /todo_lists/:todo_list_id/todo_items/:id(.:format)      todo_items#update
                         DELETE /todo_lists/:todo_list_id/todo_items/:id(.:format)      todo_items#destroy
              todo_lists GET    /todo_lists(.:format)                                   todo_lists#index
                         POST   /todo_lists(.:format)                                   todo_lists#create
           new_todo_list GET    /todo_lists/new(.:format)                               todo_lists#new
          edit_todo_list GET    /todo_lists/:id/edit(.:format)                          todo_lists#edit
               todo_list GET    /todo_lists/:id(.:format)                               todo_lists#show
                         PATCH  /todo_lists/:id(.:format)                               todo_lists#update
                         PUT    /todo_lists/:id(.:format)                               todo_lists#update
                         DELETE /todo_lists/:id(.:format)                               todo_lists#destroy
                    root GET    /                                                       todo_lists#index

Todo List Show Page Being Tested (The link on line 15 is not found by rspec when it is placed after the </table> tag)

<p id="notice"><%= notice %></p>

<p>
  <strong>List name:</strong>
  <%= @todo_list.list_name %>
</p>

<p>
  <strong>List due date:</strong>
  <%= @todo_list.list_due_date %>
</p>

<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>
<%= link_to 'New Todo Item', (new_todo_list_todo_item_path(@todo_list)) %>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Due date</th>
      <th>Description</th>
      <th>Completed</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @todo_list.todo_items.each do |todo_item| %>
      <tr>
        <td><%= todo_item.title %></td>
        <td><%= todo_item.due_date %></td>
        <td><%= todo_item.description %></td>
        <td><%= todo_item.completed %></td>
        <td><%= link_to 'Show', [@todo_list, todo_item] %></td>
        <td><%= link_to 'Edit', edit_todo_list_todo_item_path(@todo_list, todo_item) %></td>
        <td><%= link_to 'Destroy',  [@todo_list, todo_item], method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

RSPEC (rq05e is the one which kept failing)

require_relative '../config/environment'
require 'rails_helper'

describe "Module #4: Navigation Tests", :type => :routing do
    include Capybara::DSL

    before :all do
        $continue = true
    end

    around :each do |example|
        if $continue
            $continue = false
            example.run
            $continue = true unless example.exception
        else
            example.skip
        end
    end

    context "rq04" do
        scenario "TodoList scaffolding was generated and it was set as root path" do
            visit (root_path)
            expect(page.status_code).to eq(200)
            rootPage = page
            visit (todo_lists_path)
            expect(page.status_code).to eq(200)
            expect(page).to be(rootPage)
        end
        scenario "TodoItems is not directly accessible as it is nested in TodoList" do
            visit ("/todo_items")
            expect(page.status_code).to eq(404)
        end
    end

    context "rq05" do

        before :all do
            TodoItem.destroy_all
            TodoList.destroy_all
            User.destroy_all
            load "#{Rails.root}/db/seeds.rb"
        end

        context "rq05b" do

            scenario "TodoList show page displays associated todo_items" do
                tl_id = TodoList.all.sample.id
                list_items = TodoList.find(tl_id).todo_items
                visit(todo_list_path(tl_id))

                list_items.each do |l|
                    expect(page).to have_content(l.title)
                    expect(page).to have_content(l.due_date)
                    expect(page).to have_content(l.description)
                end
            end
        end

        context "rq05d" do

            scenario "TodoItem endpoint is accessible (show and destroy) through TodoList" do
                tl_id = TodoList.all.sample.id
                list_items = TodoList.find(tl_id).todo_items
                # Confirm links in list page are nested and that the
                # show page results in expected method behavior
                list_items.each do |l|
                    visit(todo_list_path(tl_id))
                    expect(page).to have_link('Show', :href => "#{todo_list_todo_item_path(tl_id, l.id)}")
                    expect(page).to have_link('Destroy', :href => "#{todo_list_todo_item_path(tl_id, l.id)}")
                    expect(page).to have_link('Edit', :href => "#{edit_todo_list_todo_item_path(tl_id, l.id)}")
                end
            end

        end

        context "rq05e" do

            scenario "TodoList page has new TodoItem link with specified URI and method" do
                tl_id = TodoList.all.sample.id
                expect(:get => new_todo_list_todo_item_path(tl_id)).to route_to(:controller => "todo_items", :action => "new", :todo_list_id => "#{tl_id}")
                list_items = TodoList.find(tl_id).todo_items
                visit(todo_list_path(tl_id))
                expect(page).to have_link('New Todo Item', :href => "#{new_todo_list_todo_item_path(tl_id)}")
            end
        end
    end

    context "rq07" do

        before :all do
            TodoItem.destroy_all
            TodoList.destroy_all
            User.destroy_all
            load "#{Rails.root}/db/seeds.rb"
        end

        subject(:user) {
            User.find_by(:username=>"jim").authenticate("abc123")
        }

        context "rq07a" do
            scenario "Links navigate from TodoList-TodoItem summary page to Item show page" do
                tl_id = TodoList.all.sample.id
                list_item = TodoList.find(tl_id).todo_items.sample
                li_id = list_item.id
                # Confirm links in list page are nested and that the
                # show page results in expected method behavior
                visit(todo_list_path(tl_id))
                expect(page).to have_link('Show', :href => "#{todo_list_todo_item_path(tl_id, li_id)}")
                click_link('Show', :href => "#{todo_list_todo_item_path(tl_id, li_id)}")
                expect(page).to have_content(list_item.title)
                expect(page).to have_content(list_item.due_date)
                expect(page).to have_content(list_item.description)
                expect(page).to have_content(list_item.completed)
            end

            scenario "Links navigate from item display back to TodoList-TodoItem summary page" do
                testList = TodoList.all.sample
                tl_id = testList.id
                list_item = TodoList.find(tl_id).todo_items.sample
                li_id = list_item.id
                # Confirm links in list page are nested and that the
                # show page results in expected method behavior
                visit(todo_list_todo_item_path(tl_id, li_id))
                expect(page).to have_link('Back', :href => "#{todo_list_path(tl_id)}")
                click_link('Back', :href => "#{todo_list_path(tl_id)}");
                expect(page).to have_content(testList.list_name)
                expect(page).to have_content(testList.list_due_date)
            end

            scenario "Link navigates from TodoList-TodoItem summary page to Item destroy" do
                TodoItemsController.skip_before_action :ensure_login
                TodoItemsController.skip_before_action :verify_authenticity_token
                tl_id = TodoList.where(:user_id=>user.id).sample.id
                list_items = TodoList.find(tl_id).todo_items
                li_id = list_items.sample.id
                # replace with navigation here
                visit(todo_list_path(tl_id))
                expect(page).to have_link('Destroy', :href => "#{todo_list_todo_item_path(tl_id, li_id)}")
                click_link('Destroy', :href => "#{todo_list_todo_item_path(tl_id, li_id)}");
                expect(TodoItem.find_by(:id => li_id)).to be_nil
            end
        end

        context "rq07c" do
            scenario "Link navigates from TodoItem display page to Item edit page and updates item" do
                tl_id = TodoList.all.sample.id
                list_item = TodoList.find(tl_id).todo_items.sample
                li_id = list_item.id
                # Confirm links in list page are nested and that the
                # show page results in expected method behavior
                visit(todo_list_todo_item_path(tl_id, li_id))
                expect(page).to have_link('Edit', :href => "#{edit_todo_list_todo_item_path(tl_id, li_id)}")
                click_link('Edit', :href => "#{edit_todo_list_todo_item_path(tl_id, li_id)}");
                expect(page).to have_content("Editing Todo Item")
                expect(find_field('todo_item[title]').value).to eq(list_item.title)
                expect(find_field('todo_item[description]').value).to eq(list_item.description)
                expect(page).to have_button("Update Todo item")
                uString = "Updated value of #{Random.new.rand(10000)}"
                fill_in "todo_item[description]", with: uString
                click_button("Update Todo item")
                expect(URI.parse(page.current_url).path).to eq("#{todo_list_path(tl_id)}")
                expect(TodoItem.find_by(:id => li_id).description).to eq(uString)
            end

            scenario "Can navigate from TodoItem edit to show via Show link" do
                testList = TodoList.all.sample
                tl_id = testList.id
                list_item = TodoList.find(tl_id).todo_items.sample
                li_id = list_item.id
                # Confirm links in list page are nested and that the
                # show page results in expected method behavior
                visit(edit_todo_list_todo_item_path(tl_id, li_id))
                expect(page).to have_link('Show', :href => "#{todo_list_todo_item_path(tl_id, li_id)}")
                click_link('Show', :href => "#{todo_list_todo_item_path(tl_id, li_id)}");
                expect(page).to have_content(list_item.title)
                expect(page).to have_content(list_item.description)
                expect(page).to have_content(list_item.due_date)
                expect(page).to have_content(list_item.completed)
            end

            scenario "Can navigate from TodoItem edit to home page with back link" do
                testList = TodoList.all.sample
                tl_id = testList.id
                list_item = TodoList.find(tl_id).todo_items.sample
                li_id = list_item.id
                # Confirm links in list page are nested and that the
                # show page results in expected method behavior
                visit(edit_todo_list_todo_item_path(tl_id, li_id))
                expect(page).to have_link('Back', :href => "#{todo_list_path(tl_id)}")
                click_link('Back', :href => "#{todo_list_path(tl_id)}");
                expect(page).to have_content(testList.list_name)
                expect(page).to have_content(testList.list_due_date)
            end
        end

        context "rq07d" do
            let(:testList) { TodoList.all.sample }
            let(:tl_id) { testList.id }
            let(:listItem) { TodoList.find(tl_id).todo_items.sample }
            let(:li_id) { listItem.id }

            scenario "Navigation link from list item view to new item form" do
                visit(todo_list_path(tl_id, li_id))
                expect(page).to have_link('New Todo Item', :href => "#{new_todo_list_todo_item_path(tl_id)}")
                click_link('New Todo Item', :href => "#{new_todo_list_todo_item_path(tl_id)}")
                expect(URI.parse(page.current_url).path).to eq("#{new_todo_list_todo_item_path(tl_id)}")
                expect(page).to have_content("New Todo Item")
            end

            scenario "New item form create adds new item and navigates to list item view" do
                # confirm that route is correct
                expect(:post => todo_list_todo_items_path(tl_id)).to route_to(:controller => "todo_items", :action => "create", :todo_list_id => "#{tl_id}")
                visit(new_todo_list_todo_item_path(tl_id))
                item = TodoItem.new(title:'Random', description:'Random entry', completed:false, due_date:Date.today)
                select item.due_date.year, from: 'todo_item[due_date(1i)]'
                select item.due_date.strftime("%B"), from: 'todo_item[due_date(2i)]'
                select item.due_date.day, from: 'todo_item[due_date(3i)]'
                fill_in 'todo_item[title]', with: item.title
                fill_in 'todo_item[description]', with: item.description
                click_button 'Create Todo item'
                new_task = TodoItem.find_by! title: "Random"
                expect(new_task.description).to eq(item.description)
                expect(page).to have_content "Todo item was successfully created."
            end

            scenario "Back from new item form returns to list item view" do
                visit(new_todo_list_todo_item_path(tl_id))
                expect(page).to have_link('Back', :href => "#{todo_list_path(tl_id)}")
                click_link('Back', :href => "#{todo_list_path(tl_id)}")
                expect(page).to have_content(testList.list_name)
                expect(page).to have_content(testList.list_due_date)
            end
        end

        context "rq07e" do
            let(:testList) { TodoList.all.sample }
            let(:tl_id) { testList.id }
            let(:listItem) { TodoList.find(tl_id).todo_items.sample }
            let(:li_id) { listItem.id }

            scenario "Completed field will be present in edit form" do
                # Go to edit page and check that completed field is present
                visit(edit_todo_list_todo_item_path(tl_id, li_id))
                expect(page.has_field?('todo_item[completed]')).to be true
            end

            scenario "Completed field will not be present in new form" do
                visit(new_todo_list_todo_item_path(tl_id))
                expect(page.has_field?('todo_item[completed]')).to be false
            end
        end

    end
 end

Aucun commentaire:

Enregistrer un commentaire