Cesare Ferrari

July 26, 2022

Testing Hotwire: creating a new document

In the previous post I started creating a Document model, to represent a document upload file. The model has a name, a description, and will have an attached file upload feature in the final version.

I have shown how to test and create a functionality to view details of a document by clicking on a list of existing documents.

In this post I will add the possibility to create a new document using Turbo Drive to show the new document form in the index page.

This means that the index page will need to have an empty turbo-frame to contain the new document form that will be loaded when we send a GET request to the new action of the DocumentsController.


System test file

We already have a test file in test/system/documents_test.rb. We now add a test for creating a document, like so:

class DocumentsTest < ApplicationSystemTestCase
  ...

  test "creating a new document" do
    visit documents_path
    assert_selector "h1", text: "Documents"

    click_on "New document"
    fill_in "Name", with: "My new document"

    assert_selector "h1", text: "Documents"
    click_on "Create document"

    assert_selector "h1", text: "Documents"
    assert_text "My new document"
  end
end

The test is simple: we visit the document index page, and make sure it’s the correct page by asserting there is an h1 tag with the text “Documents”. We then click on the “New document” link and expect a form to appear on the page itself (inside an empty turbo-frame).

We then fill in the document name and click on the “Create document” button to submit the form. Note that we still expect to see the original h1 tag with the text “Documents”, because we are still on the index page.

Since we are using Turbo Drive, we are not loading a complete new page to show the new document form. We load the form inside the index page itself.

Once we have created the document, we want the form to disappear, and the new document name appear on the index page, and our functionality will be complete.

If we run this test right now, it fails with this error:

Error:
DocumentsTest#test_creating_a_new_document:
Capybara::ElementNotFound: Unable to find link or button "New document"

The test tells us that we need to add a button to create a new document:

# app/views/documents/index.html.erb

<%= link_to "New document", new_document_path %>

Running the test now gives us a new error:

Error:
DocumentsTest#test_creating_a_new_document:
ActionView::Template::Error: undefined local variable or method `new_document_path'

We need to add the route for the new action:

# config/routes.rb

  resources :documents, only: [:index, :show, :new, :create]

As expected, we now need to create a new action in the controller, and the test tells us so:

Error:
DocumentsTest#test_creating_a_new_document:
AbstractController::ActionNotFound: The action 'new' could not be found for DocumentsController

We add the action, and we also add the corresponding template and form partial:

# app/controller/documents_controller.rb

class DocumentsController < ApplicationController
  def new
    @document = Document.new
  end
end

Template:

# app/views/documents/new.html.erb

<h1 class="text-2xl font-bold">New document</h1>

<%= render "form", document: @document %>

Form partial:

# app/views/documents/_form.html.erb

<%= form_with model: document do |f| %>

  <p>
    <%= f.label :name %>
    <%= f.text_field :name %>
  </p>

  <p>
    <%= f.label :description %>
    <%= f.text_area :description %>
  </p>

  <p>
    <%= f.submit %>
  </p>
<% end %>

If we run the test now, it fails with this error:

Failure:
DocumentsTest#test_creating_a_new_document 
expected to find visible css "h1" with text "Documents" but there were no matches.

The reason this fails is because we haven’t added any turbo-frames yet, so Rails loads a full new page as a result of calling the new action. The page replaces the index page, so the h1 element with the text “Documents” is not present any more, and this causes the test to fail.

We stop here for today.
In the next post, we will add the appropriate turbo-frames and complete the functionality.

Photo by Alena Koval


Check out my site at www.ferrariwebdevelopment.com for more blog posts and insights.