Iteration H2: Testing Our JavaScript Functionality

Now that we have application-level functionality in JavaScript code, we are going to need to have tests in place to ensure that the function not only works as intended but continues to work as we make changes to the application.

Testing this functionality involves a lot of steps: visiting the store, selecting an item, adding that item to the cart, clicking checkout, filling in a few fields, and selecting a payment type. And from a testing perspective, we are going to need both a Rails server and a browser.

To accomplish this, Rails makes use of a version of the popular Google Chrome web browser named ChromeDriver,[67] which has been augmented to include programming interfaces to enable automation, and Capybara,[68] which is a tool that drives this automation.

Tests that pull together a complete and integrated version of the software are called system tests, and that is exactly what we will be doing: we will be testing a full end-to-end scenario with a web browser, web server, our application, and a database.

When we created scaffolds in previous chapters, Rails created system tests for us that performed basic checks. Let’s run those now to make sure they are passing and that system testing is working. If you are using a virtual machine, you will need to make one change before running the tests. Edit test/application_system_test_case.rb and change :chrome to :headless_chrome so that the system tests use a browser that doesn’t need to pop up on the screen, like so:

 require ​"test_helper"
 
 class​ ApplicationSystemTestCase < ActionDispatch::SystemTestCase
» driven_by ​:selenium​, ​using: :headless_chrome​, ​screen_size: ​[1400, 1400]
 end

Let’s run the existing system tests using bin/rails test:system (we’ve truncated some of the output to fit in the book):

 $ ​​bin/rails​​ ​​test:system
  Run options: --seed 24492
 
 # Running:
 
 Capybara starting Puma...
 * Version 4.3.0 , codename: Mysterious Traveller
 * Min threads: 0, max threads: 4
 * Listening on tcp://127.0.0.1:55293
 ....[Screenshot]: depot_q/tmp/screenshots/failures_test_updating_a_Product.png
 F
 
 Failure:
 ProductsTest#​​test_updating_a_Product​​ ​​[depot_q/test/system/products_test.rb:37]:
 expected to find text "Product was successfully updated"
 in
 
 "HOME QUESTIONS NEWS CONTACT Editing Product 1 error prohibited this pro…
 
 rails test test/system/products_test.rb:27
 
 .
 
 Finished in 11.702929s, 0.5127 runs/s, 0.5127 assertions/s.
 6 runs, 6 assertions, 1 failures, 0 errors, 0 skips

Looks like we have a failure. The reason is that the system test Rails generated for us way back in Generating the Scaffold, was never updated when we added validations in Iteration B1: Validating!. Since bin/rails test doesn’t run system tests and we only just learned about them, it’s not surprising there might be a slight problem. The reason the test is failing is that we’re trying to change the book’s title to one that is already in use. We can address this by changing the test to use a different, unique, title. Make this change in test/system/products_test.rb

 test ​"updating a Product"​ ​do
  visit products_url
  click_on ​"Edit"​, ​match: :first
 
  fill_in ​"Description"​, ​with: ​@product.​description
  fill_in ​"Image url"​, ​with: ​@product.​image_url
  fill_in ​"Price"​, ​with: ​@product.​price
» fill_in ​"Title"​, ​with: ​​"Karel The Robot in a Nutshell"
  click_on ​"Update Product"
 
  assert_text ​"Product was successfully updated"
  click_on ​"Back"
 end

Now, when we run the system tests, they should all pass

  >​​ ​​bin/rails​​ ​​test:system
 Run options: --seed 22342
 
 # Running:
 
 Capybara starting Puma...
 * Version 4.3.0 , codename: Mysterious Traveller
 * Min threads: 0, max threads: 4
 * Listening on tcp://127.0.0.1:53853
 Capybara starting Puma...
 * Version 4.3.0 , codename: Mysterious Traveller
 * Min threads: 0, max threads: 4
 * Listening on tcp://127.0.0.1:53863
 .......
 
 Finished in 9.359573s, 0.7479 runs/s, 0.8547 assertions/s.
 7 runs, 8 assertions, 0 failures, 0 errors, 0 skips

This detour also showed us a bit about what system tests look like. They are written from the perspective of the user in front of a web browser and make assertions about what is in the browser itself. This is to allow our test to mimic a real user as closely as possible.

Now, let’s write the test we came here to write, which is that our JavaScript is actually working when it’s run in a web browser. We start by describing the actions and checks we want performed in test/system/orders_test.rb, which already has some tests in it from the scaffold:

 require ​"application_system_test_case"
 
 class​ OrdersTest < ApplicationSystemTestCase
  setup ​do
  @order = orders(​:one​)
 end
 
  test ​"visiting the index"​ ​do
  visit orders_url
  assert_selector ​"h1"​, ​text: ​​"Orders"
 end
 
  test ​"destroying a Order"​ ​do
  visit orders_url
  page.​accept_confirm​ ​do
  click_on ​"Destroy"​, ​match: :first
 end
 
  assert_text ​"Order was successfully destroyed"
 end
» test ​"check routing number"​ ​do
» visit store_index_url
»
» click_on ​'Add to Cart'​, ​match: :first
»
» click_on ​'Checkout'
»
» fill_in ​'order_name'​, ​with: ​​'Dave Thomas'
» fill_in ​'order_address'​, ​with: ​​'123 Main Street'
» fill_in ​'order_email'​, ​with: ​​'[email protected]'
»
» assert_no_selector ​"#order_routing_number"
»
» select ​'Check'​, ​from: ​​'Pay type'
»
» assert_selector ​"#order_routing_number"
»end
 end

As you can see, it’s only a few lines of code broken down into discrete steps: visit a URL, find the :first button with the text "Add to Cart" and click_on it. Then click_on the button labeled "Checkout". We then fill_in the three fields for our name, address, and email.

At this point in the test, we check an assumption, that the routing number field is not on the page yet. We do this using assert_no_selector, and pass it "#order_routing_number", which is a CSS selector that means “any element with an id of "order_routing_number"”. After that, we select the value "Check" from the "Pay type" selector, and then assert that the routing number text field showed up, using assert_selector. Whew!

Capybara makes all of this possible using a compact, readable API that requires very little code. For additional information and more methods, we suggest that you familiarize yourself with the domain-specific language (DSL) that Capybara provides.[69]

Now let’s run the test we just wrote:

 $ ​​bin/rails​​ ​​test:system
 Run options: --seed 26203
 
 # Running:
 
 Capybara starting Puma...
 * Version 3.12.1 , codename: Llamas in Pajamas
 * Min threads: 0, max threads: 4
 * Listening on tcp://127.0.0.1:43449
 Capybara starting Puma...
 * Version 3.12.1 , codename: Llamas in Pajamas
 * Min threads: 0, max threads: 4
 * Listening on tcp://127.0.0.1:43749
 .......
 
 Finished in 13.963120s, 0.5013 runs/s, 0.5729 assertions/s.
 7 runs, 8 assertions, 0 failures, 0 errors, 0 skips

When you run this, you’ll note a number of things. First a web server is started on your behalf, and then a browser is launched and the actions you requested are performed. Once the test is complete, both are stopped and the results of the test are reported back to you. All this based on your instructions as to what actions and tests are to be performed, and expressed clearly and succinctly as a system test.

Note that system tests tend to take a bit longer to execute than model or controller tests, which is why they are not run as a part of bin/rails test.

What We Just Did

  • We replaced a static form_select field with a dynamic list of form fields that change instantly based on user selection.

  • We used Webpacker to gather up and deliver all of the necessary JavaScript dependencies just in time to the browser to make the dynamic changes happen.

  • We used Capybara and ChromeDriver to system-test this functionality.

Playtime

Here’s some stuff to try on your own:

  • Check is not the only payment type, and routing number is not the only field that is dynamically inserted or deleted based on the payment type. Extend the system test to include other choices and other fields.

  • Add a test to verify that the Add to Cart and Empty Cart buttons reveal and hide the cart, respectively.

  • Add a test of the highlight feature you added in Iteration F3: Highlighting Changes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.82.79