Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore(site): update and refactor all custom hook tests that rely on React Router#12219

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Parkreiner merged 20 commits intomainfrommes/hook-test-revamps-4
Mar 8, 2024

Conversation

Parkreiner
Copy link
Member

@ParkreinerParkreiner commentedFeb 19, 2024
edited
Loading

Part 4 of thehooks milestone

Changes made

  • Revamps ourrenderHookWithAuth test helper function
    • Makes sure that manually callingrenderHook'srerender function does not cause state to get lost or incorrectly refreshed
    • Revamps the API for the function to ensure that have to grab "snapshots" of router state, rather than having a live, volatile link
    • Removes the router from the function's return value (React Router has flagged all of their router properties as being internal-only, so we don't want a test helper that relies on APIs that could break outside of major versions)
    • Splits off the function into a separate file so that therenderHelpers file doesn't have a bunch of noise
  • Beefs up and generalizesuseTab intouseSearchParamsKey
    • Adds support for clearing out the current key, and also exposes more options via its inputs
    • Adds test cases for all major functionality
  • MovedusePaginatedQuery to new test helper, and verified tests
  • MoveduseWorkspaceDuplication to the new test helper and verified tests

Notes

  • Figuring out how to buildrenderHookWithAuth took a lot of trial and error. I refactored the code several times to make it as clear as I could, but if there's anything that still isn't clear, please flag that, so I can update the code (or at least add a comment)
    • The function has to do some wacky stuff with React rendering behavior to getcreateMemoryRouter andrenderHook wired up and overcome their incompatible APIs
    • That said, the function does everything through React Router's public APIs (no reading internals that they don't document anywhere), so this code should be pretty stable
    • I tried as hard as I could to make the interface for the function as nice as possible, so you can ignore the chaotic implementation details

@ParkreinerParkreiner self-assigned thisFeb 19, 2024
@ParkreinerParkreiner changed the titlechore: revamp all custom hook tests using React Routerchore: revamp all custom hook tests that rely on React RouterFeb 19, 2024
@ParkreinerParkreiner changed the titlechore: revamp all custom hook tests that rely on React Routerchore: update and refactor all custom hook tests that rely on React RouterFeb 19, 2024
@ParkreinerParkreiner changed the titlechore: update and refactor all custom hook tests that rely on React Routerchore(site): update and refactor all custom hook tests that rely on React RouterFeb 19, 2024
@github-actionsgithub-actionsbot added the staleThis issue is like stale bread. labelFeb 27, 2024
@ParkreinerParkreiner added the siteArea: frontend dashboard labelFeb 28, 2024
@Parkreiner
Copy link
MemberAuthor

Bumping this to prevent it from getting stale – had to put it off to get the clipboard fixes/tests done faster, but I will be getting back to this

@github-actionsgithub-actionsbot removed the staleThis issue is like stale bread. labelFeb 29, 2024
@Parkreiner
Copy link
MemberAuthor

Nearly got this thing done. The tests should be stable now, but one thing I do want to do is remove therenderHookWithAuth's reliance on internal React Router implementation details

(The React Router router objects have a ton of properties that you can freely access, but they're all marked as 'for internal use only'. Not sure if those comments got added after I made the initial version of the helper, or if I missed them)

@ParkreinerParkreiner requested review froma team andaslilac and removed request fora teamMarch 4, 2024 16:56
@ParkreinerParkreiner marked this pull request as ready for reviewMarch 4, 2024 16:56
Copy link
Member

@aslilacaslilac left a comment

Choose a reason for hiding this comment

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

The 20 line comment about how cursed this has to be because we're using the undocumentedRouterProvider component has me really concerned about this. I know we were already using that component, but I don't understand why we're using an undocumented component over a component likeMemoryRouter 😅

@@ -45,28 +49,23 @@ describe(`${useWorkspaceDuplication.name}`, () => {
expect(result.current.isDuplicationReady).toBe(false);

for (let i = 0; i < 10; i++) {
rerender({ workspace: undefined });
voidrerender({ workspace: undefined });
Copy link
Member

Choose a reason for hiding this comment

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

this really isn't supposed to be anawait?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Typo I forgot to fix – good catch


const parsedParams = new URLSearchParams(router.state.location.search);
const extraMetadataEntries = [
const extraMetadataEntries: readonly [string, string][] = [
Copy link
Member

Choose a reason for hiding this comment

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

why the switch fromas const?

Copy link
MemberAuthor

@ParkreinerParkreinerMar 8, 2024
edited
Loading

Choose a reason for hiding this comment

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

I felt like it would surface any accidental errors in a better way, and that it does a better job of communicating intent

With the previous code, I could do something like this:

constextraMetadataEntries=[["mode","duplicate"],["name",`${MockWorkspace.name}-copy`],["version",MockWorkspace.template_active_version_id],functionobviouslyWrong(){},null,["forgotToAddTheSecondTupleElement"]]asconst;

And this would be valid still – the underlying type would get broadened. So while the type mismatch would get caught down the line, redefining the type to be an array of string tuples tells you what types should go in, and is more defensive against typos

* we're not relying on internal React Router implementation details that
* could break at a moment's notice
*/
let escapedLocation!: Location; // Definite assignment via !
Copy link
Member

Choose a reason for hiding this comment

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

well that's a bit of typescript I've never seen before. I'm wary of comments that just say "this line of code means x" tho.

Copy link
MemberAuthor

@ParkreinerParkreinerMar 8, 2024
edited
Loading

Choose a reason for hiding this comment

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

It's less a "this line of code means x", and more a "here's a bigger warning sign for something that silences the compiler and is only a single, easy-to-miss character", but I get what you mean

Wish there were a more obvious syntax, but because of grammar rules, you can't even insert type assertions

@aslilac
Copy link
Member

our testing code seems to differ substantially from the sort of stuffhttps://v5.reactrouter.com/web/guides/testing recommends

@Parkreiner
Copy link
MemberAuthor

Parkreiner commentedMar 8, 2024
edited
Loading

@aslilac So there's a couple of things this is trying to get around. Sorry for the walls of text, and I want to be very clear: this isn't directed at you, but I'm also trying to get this put into writing before I forget anything:

  1. MemoryRouter just isn't nearly as ergonomic ascreateMemoryRouter for testing setup
    • WhileMemoryRouter still works, the main issue for it is that it's incredibly hard to generalize into a single test helper.MemoryRouter needs you to supply an individualRoute component for every single path segment you want to test for, and make sure that eachRoute has some kind of component associated with it. This is because under the hood, React Router is processing and stripping the children JSX it receives into a JSON object of what routes to set up. You can't just go "I want to setup a component for/a/b/c, and I'm okay if going anywhere else causes an error"
    • createMemoryRouter doesn't have this limitation – you can go "make me a route for/a/b/c and ignore everything else", and it'll fill in the missing pieces behind the scenes. But the tradeoff is that the component that receives the router no longer acceptschildren
    • It would be possible to make a helper to help interface our tests with the originalMemoryRouter, but it's going to require recursive components and a bunch of dummy components. I considered it for a little bit, but I stopped myself because that felt like it'd be even more complex
  2. The test examples you linked are for React Router v5 – and v6 is notorious for its breaking changes from v5 (as in, genuinely made a lot of people mad)
    • The very first example they show in the v5 docs is no longer valid (and that's on them). Trying to haveSidebar be a direct child ofMemoryRouter will immediately break
    • Though the real issue is that despite v6 being 2.5 years old, they don't have any modern testing documentation at this point
  3. Honestly, I feel like the React Router people haven't really been concerned about ergonomics outside of Remix that much
    • They don't stabilize the function references for any of their custom hooks
    • They just expect you to ignore the ESLint rules around dependency arrays all over the place, and even codify that assumption into their docs
  4. The problem of testing React Router custom hooks has been a problem for ages, and the Remix team just doesn't seem that interested in supporting the use case
    • I scoured StackOverflow and GitHub for ages, and the very few solutions I found were also hacks, but they didn't address every possible thing you would want from a custom hook test
    • This issue just got updated because other people are still struggling with this:
      # Formatting link like this to avoid pinging themhttps://github.com/remix-run/react-router/issues/7759
  5. Also, just making sure: were you looking at the docs for v5? The page forRouterProvider is right here

Now all that said, I can go back to the drawing board on this. What are your main concerns, either from an interface, or an implementation standpoint?

@aslilac
Copy link
Member

gotta love that the top google search result was the docs for a 3 year old version of the library 🙃 sorry about that. let me go read the right docs and rereview with that in mind.

Copy link
Member

@aslilacaslilac left a comment

Choose a reason for hiding this comment

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

I gotta admit, I'm still very unhappy about this code, but I at least sort of get why it has to be this nasty. 😅

) {
await waitFor(() => expect(result.current.isDuplicationReady).toBe(true));
result.current.duplicateWorkspace();
void act(() =>result.current.duplicateWorkspace());
Copy link
Member

Choose a reason for hiding this comment

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

anothervoid/await?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Yup – will fix

@Parkreiner
Copy link
MemberAuthor

@aslilac Yeah, believe me – I would throw this into a fire if I could

@ParkreinerParkreiner merged commit4d42c07 intomainMar 8, 2024
@ParkreinerParkreiner deleted the mes/hook-test-revamps-4 branchMarch 8, 2024 23:31
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsMar 8, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@aslilacaslilacaslilac approved these changes

Assignees

@ParkreinerParkreiner

Labels
siteArea: frontend dashboard
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@Parkreiner@aslilac

[8]ページ先頭

©2009-2025 Movatter.jp