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

[POC] Custom test renderer #1669

Closed
wants to merge 54 commits into from
Closed

[POC] Custom test renderer #1669

wants to merge 54 commits into from

Conversation

mdjastrzebski
Copy link
Member

@mdjastrzebski mdjastrzebski commented Sep 15, 2024

Summary

Experimental test renderer replacing React Test Renderer, which is being deprecated.

Overview

The new renderer (React Native Test Renderer?) is a simple renderer created using react-reconciler package. It operates only on host elements and does not expose composite elements at all. It's still very simple and event propagation is still handled by RNTL.

Details

  1. This simplified most of the code that was responsible for hiding composite components from the output.
  2. FireEvent API relied on calling event handlers also on composite elements. This is no longer working and we only invoke host element event handlers.
  3. In most cases this is not problematic, except for Pressable/Touchable where onPress exists only on composite level, while on host element level it's onResponderGrant + onResponderRelease pair. In order to minimise the impact on the existing tests fireEvent.press actually calls onResponderGrant + onResponderRelease to trigger onPress in such case.
  4. UNSAFE_xxx queries (*byType and *byProps) and props (UNSAFE_container) no longer return composite elements, and can be either removed (high time) or kept but without UNSAFE_ prefix as they are now safe.
  5. Rendering string outside Text component is now automatically detected on renderer error and triggers a throw, as it would in React Native renderer.

Test status

All tests passing. Some tests had been disabled due to no longer being relevant.

@mdjastrzebski mdjastrzebski marked this pull request as ready for review October 15, 2024 11:23
@mdjastrzebski mdjastrzebski changed the title [Experimental] Custom test renderer [POC] Custom test renderer Oct 15, 2024
# Conflicts:
#	package.json
#	src/fire-event.ts
#	src/helpers/component-tree.ts
#	src/matchers/__tests__/to-be-checked.test.tsx
#	src/matchers/__tests__/to-be-partially-checked.test.tsx
#	src/render.tsx
#	src/user-event/utils/dispatch-event.ts
#	yarn.lock
Copy link

codecov bot commented Nov 8, 2024

Codecov Report

Attention: Patch coverage is 90.33613% with 46 lines in your changes missing coverage. Please review.

Project coverage is 93.48%. Comparing base (a282d1e) to head (81b73f1).
Report is 91 commits behind head on main.

Files with missing lines Patch % Lines
src/act.ts 50.00% 17 Missing ⚠️
src/queries/unsafe-props.ts 48.27% 15 Missing ⚠️
src/queries/unsafe-type.ts 58.62% 12 Missing ⚠️
src/matchers/utils.tsx 86.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1669      +/-   ##
==========================================
- Coverage   95.51%   93.48%   -2.04%     
==========================================
  Files          99       94       -5     
  Lines        5400     5435      +35     
  Branches      857      886      +29     
==========================================
- Hits         5158     5081      -77     
- Misses        242      354     +112     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@pierrezimmermannbam
Copy link
Collaborator

The fact that composite components aren't there anymore makes fireEvent very fragile I think because we cannot guarantee anymore that you can use it with the name of any react prop. Even with your fix on fireEvent.press, it would break if users used fireEvent(element, 'press') and it would also break for pressOut or pressIn on Pressable.

I wonder if we should consider removing it completely? Or maybe making it deprecated at first to ease migration but still aim at removing it in the long term. I don't think fireEvent would make sense anymore without composite elements and it would also make things simpler for users since there would not be two similar APIs anymore (userEvent and fireEvent). There are some downsides to this though:

  • there would be some tests that could not be written anymore, although userEvent should be able to fill the gap in most situations but these tests may be written differently, more from a user perspective
  • using userEvent kind of requires using fake timers, which not everyone does. This would make migration even harder but at the same time it would make everybody's tests better imo

Overall it would be a very difficult migration but that would make user's tests better in the end I think so I do think it's a reasonable option.

Wdyt @mdjastrzebski @MattAgn ?

@mdjastrzebski
Copy link
Member Author

I think we need to keep fireEvent as a way to trigger any random host event handler. RN "host" event handlers seem pretty stable due to the fact how components are mocked in RN (there is no true composite View, just mock forwarding everything as is from composite View to pseudo-host View). As I have written before, if RN mocks change, we will have a lot more things to change in RNTL, yet they remained surprisingly stable over the years.

I deeply care about great many RN developers that wrote and/or now maintain large test bases full of fireEvent calls. We might consider soft-deprecating (= warning) fireEvent.press, fireEvent.changeText, fireEvent.scroll and keep fireEvent(elem, eventName, payload) form. That way would give them a path (and time) to gradually migrate either to recommended User Event interactions if they exist or just use fireEvent(element, eventName) if they do not exist.

Regarding User Event requiring fake timers, I think that many people are actually using them without fake timers, accepting the delay on press event for pressables. It's kinda like writing sleep(130) in your tests. You can have that with real times, it won't be optimal, but it will work. That's why I do not think that UE makes fake timers a strict requirement, it just makes your tests run faster.

@mdjastrzebski
Copy link
Member Author

Closing as replaced by #1705.

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.

2 participants