Skip to content

[#4922] handle invalid date ranges in date range input#5192

Merged
dorner merged 18 commits into
rubyforgood:mainfrom
danielabar:4922-v2-handle-invalid-date-range-filter
May 23, 2025
Merged

[#4922] handle invalid date ranges in date range input#5192
dorner merged 18 commits into
rubyforgood:mainfrom
danielabar:4922-v2-handle-invalid-date-range-filter

Conversation

@danielabar
Copy link
Copy Markdown
Collaborator

Resolves #4922

Description

Fixes the issue where under very specific circumstances, a user could enter invalid data into the date range input (used to filter many views like Donations, Purchases, etc.) and have that data submitted to the server. In this case, an error would be raised and result in 500 Server Error page.

It was difficult to reproduce because most of the time, Litepicker.js (library which is bound to the date range input) is active and has its own validation logic for date ranges, such that if something invalid is entered, it will not update the state of the input, which results in it going back to the default value when user blurs away, so their invalid data never sticks around.

But if user tabs into the date range field, then the Litepicker.js events are not registered. In this case, the user can type in whatever they want without Litepicker being aware of it. Then if user hits Enter, the invalid date range will be submitted to the server. Server side logic was raising an error in this case. This has been fixed to gracefully handle it with a flash notice. See app/helpers/date_range_helper.rb.

Also, if a user tabs or clicks away from the date range field (after having tabbed in and entered invalid data), then some new client side JS has been added to alert them. See app/javascript/controllers/date_range_controller.js

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

For automated testing, the shared example spec/support/date_range_picker_shared_example.rb was modified to add cases for server and client side error handling of invalid input. This is run by all system tests that cover filtering: Transfer management, Donations, Purchases, Requests, Distributions, Adjustment management.

Quick way to focus on just these: bundle exec rspec spec/system -e "when entering an invalid date range"

For manual testing:

  1. Log in as org admin
  2. Navigate to Purchases -> All Purchases (should work the same for any form that uses date range for filtering)
  3. Press the tab key multiple times until the focus is on "Purchase date range" field
  4. Type in something invalid like "nov 08 - feb 08"
  5. Hit Enter - should get the flash notice with date range reset to default

Repeat steps 1 - 3, but then instead of hitting Enter, click or tab away (you still need to tab in to the field though) - this time an alert displays.

In either case, you can click into the date range and fix the invalid date, then submit the form and it should work.

Screenshots

image

image

image

* Fixed issue where tabbing into date range field and typing invalid
  data bypassed Litepicker validation
* Updated DateRangeHelper to catch parsing errors and show flash notice
  instead of raising 500
* Added custom client-side check in Stimulus controller to catch bad
  input on blur
* Introduced global isLitePickerActive flag in application.js so that
  custom date range controller can avoid alerting user if Litepicker
  is open
@danielabar
Copy link
Copy Markdown
Collaborator Author

danielabar commented May 12, 2025

Note some system tests have been failing on CI (Ferrum unknown target exception), but all tests pass locally.

@cielf
Copy link
Copy Markdown
Collaborator

cielf commented May 12, 2025

Given how hard it is to recreate, I'm surprised how frequently we get them! (one or two a month) There's probably some one person who just does things this way.

Thank you for sussing it out! It LGTM functionally (in a perfect world, we'd have the same behaviour no matter how they got there, but this will do IMO). Over to @dorner for technical wisdom, etc.

@cielf cielf requested a review from dorner May 12, 2025 23:22
Copy link
Copy Markdown
Collaborator

@dorner dorner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One admin question, otherwise looks good to me.

Not sure what's going on with the system specs, but they seem to be failing consistently. We need a way to fix them if we want this merged.

Comment thread app/helpers/ui_helper.rb Outdated
def filter_button(options = {}, data = {})
_button_to(
{ icon: "filter", type: "primary", text: "Filter", size: "md" }.merge(options),
{ data: { test_id: "filter-button" }.merge(data) }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this added by accident? I don't see it used.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a data-test-id to the filter button which is used in the shared example system spec:

page.execute_script("document.querySelector('[data-test-id=\"filter-button\"]').click();")

Normally would simply use the Capybara click method with text "Filter", but due to event handling required to reproduce this issue, had to use execute_script with querySelector. And there wasn't an easy way to select a button by its text. So this was to ensure that the test is clicking the correct button, in case there should be more buttons added to any of the pages in the future.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, after working through the CI failing tests, this is no longer needed, removed.

@danielabar
Copy link
Copy Markdown
Collaborator Author

danielabar commented May 17, 2025

One admin question, otherwise looks good to me.

Not sure what's going on with the system specs, but they seem to be failing consistently. We need a way to fix them if we want this merged.

I've seen those kind of test failures on CI (Ferrum::NoSuchTargetError), on this and other projects that use Cuprite, but usually they resolve with a re-run. And all the tests do pass locally so this is a strange one.

I even tried running the tests locally with the same seed that's failing on CI, in case there's a specific sequence of test execution that causes the failures:

bin/rspec --seed 18633

But still they pass locally.

There have been some commits on main since this PR was submitted so I could try to rebase (or is that not allowed after PR is submitted?) and see if that makes a difference.

@danielabar
Copy link
Copy Markdown
Collaborator Author

Update on system tests: I temporarily commented out the new invalid date range tests, and then all the tests pass on CI: https://github.com/rubyforgood/human-essentials/actions/runs/15084551153

Will investigate...

@danielabar
Copy link
Copy Markdown
Collaborator Author

First failure is for the date range, so possibly something here is causing a cascade of failures:

Shared Example Group: "Date Range Picker" called from ./spec/system/purchase_system_spec.rb:83

     1.1) Failure/Error: expect(page).to have_css(".alert.notice", text: "Invalid Date range provided. Reset to default date range")

          Ferrum::TimeoutError:
            Timed out waiting for response. It's possible that this happened because something took a very long time (for example a page load was slow). If so, setting the :timeout option to a higher value might help.
          # ./spec/support/date_range_picker_shared_example.rb:120:in 'block (3 levels) in <top (required)>'

@cielf
Copy link
Copy Markdown
Collaborator

cielf commented May 18, 2025

Just FYI -- we had 3 different people run into this this week. Still seems weird, but people who do a lot of data entry probably use tabs to move around more than I do.

@danielabar
Copy link
Copy Markdown
Collaborator Author

Still investigating CI test failures - unfortunately since it passes locally, need to commit a bunch of temp changes to the test to see how it fails on CI.

Issue seems to be that JS runs overall slower on CI, and it's difficult to simulate exact user interaction in scenario that triggers server side validation. So when trying to simulate user submitting invalid data to server, when CI runs, the blur event is being triggered before form is submitted, so it displays the JS alert instead of the flash notice.

Continuing to investigate...

@danielabar
Copy link
Copy Markdown
Collaborator Author

@dorner @cielf Fixed the date range system tests that were failing on CI. Since it could only be reproduced on CI, ended up with a bunch of experimental commits on this branch. I know we're not supposed to rebase after PR is submitted, so I could leave them, or if you prefer, I could clean them up.

@cielf
Copy link
Copy Markdown
Collaborator

cielf commented May 20, 2025

@dorner's call on that, methinks.

Copy link
Copy Markdown
Collaborator

@dorner dorner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with this!

@dorner dorner merged commit f0f2f61 into rubyforgood:main May 23, 2025
12 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2025

@danielabar: Your PR [#4922] handle invalid date ranges in date range input is part of today's Human Essentials production release: 2025.06.01.
Thank you very much for your contribution!

GiovannyCordeiro pushed a commit to GiovannyCordeiro/human-essentials that referenced this pull request Jun 6, 2025
…byforgood#5192)

* [rubyforgood#4922] handle invalid date ranges in date range input

* Fixed issue where tabbing into date range field and typing invalid
  data bypassed Litepicker validation
* Updated DateRangeHelper to catch parsing errors and show flash notice
  instead of raising 500
* Added custom client-side check in Stimulus controller to catch bad
  input on blur
* Introduced global isLitePickerActive flag in application.js so that
  custom date range controller can avoid alerting user if Litepicker
  is open

* temporarily remove invalid date range system tests to investigate CI failures

* Revert "temporarily remove invalid date range system tests to investigate CI failures"

This reverts commit f8ccea2.

* temp changes to investigate js timing failure for system tests on ci

* remove attempt to focus tests for ci failure investigation

* temp ci failure investigation - run only distribution system tests which include invalid date range testing

* temp investigation for ci failure - try to get to failure quickly

* investigate ci failure - attempt to submit form without js having a chance to simulate invalid data getting to server

* temp ci investigation - focus only on server side validation test

* more ci failure investigation - how far does it get before js alert popups up

* experiment to temp disable custom js validation in test to simulate server side validation

* now that server side validation test passes on ci, try also with client side validation test

* try with all tests

* cleanup CI test failure investigation code

* remove unused data test id from filter button

* document disable validation option for client side JS

* consolidate all js execution in test

* undo changes to rspec system workflow file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

If someone *does* put in an invalid date range, it should be handled gently (shouldn't do a 500)

3 participants