Debugging Tips - department-of-veterans-affairs/caseflow GitHub Wiki

Debugging Tips

This page provides an introduction to debugging in Caseflow. Post your questions and ask someone to answer it on this page.

Also see these:

ActiveRecord vs ActiveModel

ActiveRecord vs. ActiveModel

  • ActiveRecord - e.g., Appeal or Tasks in Caseflow's DB
  • ActiveModel - e.g., LegacyAppeals in VACOLS

Related: where vs. find

> Task.where(id: [1, 2]).class
=> Task::ActiveRecord_Relation

> Task.find([1, 2]).class
=> Array

URLs handled by a Rails Controller

Given a controller, look for the controller name on the right-hand side of bundle exec rake routes output (or http://localhost:3000/rails/info/routes if Caseflow is running). The left-side shows the URL (aka, API call). Grep for that URL in js and jsx code to find pages and components that use the given controller.

For more, see https://reinteractive.com/posts/188-rails-discovery-magical-routes-part-1-major-usages

Which React component is this web element?

  • Install React Developer Tools browser extension.
  • Load the relevant web page.
  • Open Developer Tools in the browser; open the "Components" tab. A hierarchy of React components should be shown.
  • Click on the square-with-arrow icon on the upper left (but within the tab), then select the web element on the web page.
  • On the right side of the tab, scroll down to the "rendered by" section to see relevant React components.

Given a SomeComponentView.jsx, how do I navigate to it?

  • Trial and error
  • More experience with the Caseflow UI and how it is used by users. See training material.
  • Find RSpecs that use the view to get an idea when it is used.

How is a web element populated?

  • Install Redux DevTools browser extension
  • Load the relevant web page.
  • Open Developer Tools in the browser
    • Open the "Redux" tab. A hierarchy of React components should be shown.
      • Open the "Network" tab. You may have to reload the web page or reopen Developer Tools.
        • Click on rows to see the "Request URL" on the right side of the tab. These requests are handled by Rails controllers (see other section).
  • Redux explanation with example from Queue:
    • React components dispatch Redux actions, which get processed by Redux reducers based on the action type. All reducers are contained in a single agglomerate reducer, which returns a JavaScript object used to update the Redux store.
    • client/app/queue/reducers.js: defines reducers associated with names that will be seen in the "Redux" developer tool tab. The result of these reducers are used to modify the state of the store.
    • client/app/queue/QueueActions.js defines functions that use ApiUtil to submit a request to the backend and maps the response to an action object, which has a type that is used to select a reducer and by convention corresponds to names in the "Redux" developer tool tab. The action object also has a payload that holds response data received from the backend.
  • Given an updated Redux store, any React component can retrieve store data. To do this, update the jsx file as follows:
    • Update the mapStateToProps function to extract specific data from the Redux state and return an object that is used as the props for React components.
    • TODO: describe mapDispatchToProps
    • Update propTypes to define the shape of the data.
    • Use the props within the React component.

Queue Frontend Development

How do you find a hearing?

  • Hearing for AMA appeals
    • Find using the appeal_id: Hearing.find_by(appeal_id: 864)
    • Find using the uuid:
      • Hearing.find_by(uuid: "25184d31-36c8-4bb0-864f-af3541de46fe")
      • or Hearing.find_hearing_by_uuid_or_vacols_id("25184d31-36c8-4bb0-864f-af3541de46fe")
  • LegacyHearing for Legacy appeals
    • Find using the vacols_id:
      • LegacyHearing.find_by(vacols_id: "707133")
      • or Hearing.find_hearing_by_uuid_or_vacols_id("707133")

How do you look up an appeal using the decision document id?

  • AttorneyCaseReview.find_by(document_id: "12345-12345678").appeal

Create Colocated Tasks in Dev/Demo

https://dsva.slack.com/archives/CJL810329/p1581700299284200

Log in as “VLJ_SUPPORT_ADMIN”

Create a bunch of colocated tasks to play with:

ColocatedTask.actions_assigned_to_colocated.map(&:to_sym).each { |action|
  FactoryBot.create(:ama_colocated_task, action, 
    assigned_by: User.first,
    assigned_to: Colocated.singleton, 
    appeal: FactoryBot.create(:appeal), 
    parent: FactoryBot.create(:task, assigned_to: User.first, assigned_by: User.first) ) }

Application Startup

  • Different environments are specified in config/environments/: demo, development, prod, staging, test
  • Base settings are in config/application.rb, including Rails console and pry, and are overridden by environment settings
  • Database settings are in config/database.yml
  • Application configurations are in config/initializers/; all .rb files in this directory are automatically loaded
    • fake_dependencies.rb calls Fakes::Initializer.app_init!(Rails.env), which for certain configurations:
      • sets User.authentication_service = Fakes::AuthenticationService
      • and User.authentication_service.user_session = { ... "FAKEUSER" }
      • This mimics ApplicationController.current_user.

User Sessions

About sessions and ActionController Session details.

  • User.authenticate! authenticates as a specific user or a default user with specified css_id and/or roles (see method definition in StubbableUser)
    • Feature RSpecs (those within ./spec/feature) and other RSpecs use User.authenticate!
    • It sets RequestStore.store[:current_user] = user and User.stub = user
    • unauthenticate! resets these
  • RequestStore.store[:current_user] = user sets the current user as user.
    • Many non-feature RSpecs use RequestStore.store[:current_user] directly
    • It gets overridden in ApplicationController.current_user with every HTTP request based on info in the request.
  • Some early code uses User.stub to set the current user.

User.authenticate! and User.stub are provided by StubbableUser, which is only available for RSpec tests.

  • In StubbableUser, if stub is set, it is returned for User.from_session(session), which is used for authentication in ApplicationController

Authenticating in the Rails console

Below are two methods to authenticate as any user in the Rails console (of the development environment).

  • Method 1 makes use of Fakes::AuthenticationService providing .default_user_session, which is used when no one is authenticated. See User.from_session(session), which is used by StubbableUser.authenticate! (aka User.authenticate!).
  • Method 2 uses the '/test/set_user' route.
User.authentication_service
=> Fakes::AuthenticationService

# Who I want to authenticate as
me=User.find(3)

# Method 1: Set me the default user
# Only works if you haven't authenticated yet (e.g., just started a new Rails console).
# But you don't need a CSRF token
User.authentication_service.user_session = User.authentication_service.get_user_session(me.id)
# To debug, add `binding.pry` in app/models/user.from_session(session)
app.get '/';  app.response.body[/userDisplayName.*/]

# Method 2: Get CSRF token and authenticate
app.get '/';
parameters = { authenticity_token: app.session.to_hash["_csrf_token"] }
# Repeat this for different user_ids as many times as you want
app.post "/test/set_user/#{me.id}", params: parameters
app.get '/';  app.response.body[/userDisplayName.*/]

# To log out
app.get '/logout'

(Going to http://localhost:3000/test/users/me will show the _csrf_token in the browser.)

Get tasks for a Legacy Appeal

Certain tasks for legacy appeals are not saved to Caseflow's database. They are transient tasks and are created in memory based on VACOLS data using LegacyWorkQueue.tasks_by_appeal_id(vacols_id). The transient tasks are defined in app/models/legacy_tasks/.

To get the appeal's assignment history, pp appeal.location_history.map(&:summary).