Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save screenshot path on system test failure #48863

Merged
merged 1 commit into from Aug 3, 2023
Merged

Conversation

matteeyah
Copy link
Contributor

@matteeyah matteeyah commented Aug 1, 2023

Motivation / Background

Lots of CI tools support showing a failure screenshot somewhere in their UI (e.g. GitLab). I want to persist the screenshot path so these tools can pick up the screenshot and visually display it.

Detail

This Pull Request changes ActionDispatch::SystemTesting::TestHelpers::ScreenshotHelper to save the screenshot path in the test metadata on failure.

Additional information

Bumping minitest to 5.19.0 is required because the metadata changes were added in then.

https://github.com/minitest/minitest/blob/master/History.rdoc#5190--2023-07-26-

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one change. Changes that are unrelated should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message. Ex: [Fix #issue-number]
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature. Minor bug fixes and documentation changes should not be included.

return unless failed? && supports_screenshot? && Capybara::Session.instance_created?

take_screenshot
metadata[:failure_screenshot_path] = absolute_image_path
Copy link
Member

Choose a reason for hiding this comment

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

Bumping minitest in the gemfile only does it for the Rails CI builds but not applications. We locked an older Ruby to an older minitest becasue of the kwargs changes. You can see this is causing the tests to fail for that one here: https://buildkite.com/rails/rails/builds/98449#0189b14e-eeaf-4d2d-9b0f-5382c140fe23/1062-1226

We can't set this or test it unless metadata is defined. We also don't want to force applications to upgrade to 5.19 for this feature.

Copy link
Contributor Author

@matteeyah matteeyah Aug 2, 2023

Choose a reason for hiding this comment

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

I'm a big fan of your work @eileencodes! I feel like talking to a real life action heroine. 😊

Back to reality - I'm a new contributor so I'll rehash your comment to make sure I understood it properly. You're saying we need to check if metadata is defined here before doing anything with it? 🤔 This will then allow downstream apps to use either version of minitest.

Is that preferable to backporting the functionality to older versions of minitest? Not sure if the the minitest maintainer is open to the idea, but I could try asking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a check for the existence of metadata.

To make the tests work, I skipped the test dynamically if metadata is not defined on Minitest::Runnable. This leaks a little bit of implementation into the test, but I wasn't sure how else I could make the test work for older versions of minitest.

I also contemplated adding an additional test case that checks how the helper behaves in a scenario when it's running with an older version of minitest which doesn't have metadata defined. i.e. to make sure that it doesn't raise an error. But in order to do that, I'd need to undefine metadata then redefine it after running the test. I opted against this, because I deemed the risk of the test leaking bigger than the risk of the error that it's trying to prevent.

@@ -152,6 +152,24 @@ def setup
assert_match %r|url=artifact://.+?tmp/screenshots/1_x\.png|, display_image_actual
end

test "take_failed_screenshot persists the image path in the test metadata" do
skip "Older versions of Minitest don't support test metadata." unless Minitest::Runnable.instance_methods(false).include?(:metadata)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
skip "Older versions of Minitest don't support test metadata." unless Minitest::Runnable.instance_methods(false).include?(:metadata)
skip "Older versions of Minitest don't support test metadata." unless Minitest::Runnable.method_defined?(:metadata)

Copy link
Contributor Author

@matteeyah matteeyah Aug 3, 2023

Choose a reason for hiding this comment

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

I changed it with your suggestion.

return unless failed? && supports_screenshot? && Capybara::Session.instance_created?

take_screenshot
metadata[:failure_screenshot_path] = absolute_image_path if defined?(metadata)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
metadata[:failure_screenshot_path] = absolute_image_path if defined?(metadata)
metadata[:failure_screenshot_path] = absolute_image_path if Minitest::Runnable.method_defined?(:metadata)

Otherwise this code could be confused by a user defined metadata method in the test class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It makes sense being more explicit when checking for this. I applied your suggestion. Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

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

This now fails when minitest isn't the test runner, for example when rspec is the runner. Is there an additional condition that can be added to detect that minitest is the runner and not just loaded?

Copy link
Member

Choose a reason for hiding this comment

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

@albus522 Does the test fail or is there just no additional metadata? Could you open an issue with a repro? 🙇

Copy link
Member

Choose a reason for hiding this comment

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

@zzak @matteeyah I reproduced the error reported by @albus522 with a video.
Let me know how I can help solving this. Thanks 🙇

rspec.rails7.issue.1080.mov

Copy link
Member

Choose a reason for hiding this comment

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

This was fixed today by @JonRowe in rspec/rspec-rails#2704 🎉

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the thorough explanation! Glad it was fixed downstream. 🙏

@casperisfine
Copy link
Contributor

Please squash your commits, after that it's good for me.

@byroot byroot merged commit ee3117b into rails:main Aug 3, 2023
9 checks passed
@byroot
Copy link
Member

byroot commented Aug 3, 2023

Thank you!

@davidwessman
Copy link

Exactly what I wanted in #44624 😍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants