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

Components: Update ExternalLink to support onClick handler #45214

Merged

Conversation

Initsogar
Copy link
Contributor

What?

Fixes #45212

The idea is to make <ExternalLink> component to handle onClick events again, based on the issue #45212. Also it includes some unit testing for this component.

Why?

onClick handler on <ExternalLink> component is currently being used in multiple instances in Jetpack monorepo to record tracking events, and we consider it is necessary to include custom logic on that handler.

This stopped working after a change implemented for validating anchor links in #42259.

How?

We are creating a new function for the onClick handler to:

  • Validate and execute onClick whether it is passed as a prop.
  • Validate if the link is an internal anchor, so we can prevent default action to not impact what was implemented on #42259

Testing Instructions

You can run unit tests for this:
npm run test:unit -- external-link/test/index.tsx

@Initsogar Initsogar requested a review from ajitbohra as a code owner October 21, 2022 18:30
@github-actions github-actions bot added the First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository label Oct 21, 2022
@github-actions
Copy link

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @Initsogar! In case you missed it, we'd love to have you join us in our Slack community, where we hold regularly weekly meetings open to anyone to coordinate with each other.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

Copy link
Contributor

@alexstine alexstine left a comment

Choose a reason for hiding this comment

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

@Initsogar Thanks for your PR. I do like how the code is a little cleaner now and makes more sense.

One thing that will be needed, the changelog will need updating at packages/components/changelog.md. Probably call this a bug fix if it is currently not working.

@alexstine alexstine added [Type] Bug An existing feature does not function as intended [Package] Components /packages/components labels Oct 21, 2022
@mirka mirka requested review from mirka, chad1008 and ciampo October 21, 2022 19:15
@ciampo
Copy link
Contributor

ciampo commented Oct 24, 2022

@chad1008 , would you be able to review this PR ?

Copy link
Contributor

@chad1008 chad1008 left a comment

Choose a reason for hiding this comment

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

Changes to the component look good to me 🙂. I've included some inline comments on the new unit tests.

Other than that I think all this will need is a CHANGELOG entry!

packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved

fireEvent( component, clickEvent );

expect( clickEvent.defaultPrevented ).toBe( true );
Copy link
Contributor

Choose a reason for hiding this comment

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

With the suggested change to userEvent, you'll need a different test of the defaultPrevented property. Maybe something like:

const onClickMock = jest.fn();

// ...

expect( onClickMock ).toHaveBeenCalledTimes( 1 );
expect( onClickMock ).toHaveBeenLastCalledWith(
  expect.objectContaining( {
    defaultPrevented: true
  } )
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@chad1008 The idea of this specific test case is to validate it is properly preventing default action if it is an anchor link, without passing onClick prop to our component (I will update the test case name). I'm trying to find a way to accomplish this using userEvent, but don't find any yet. Do you have any idea how we could handle it?

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 think we can mock the onClick after rendering the link from the component and validate we are receiving the defaultPrevented: true. Something like:

const user = setupUser();

render(
	<ExternalLink href="#test">I&apos;m an anchor link!</ExternalLink>
);

const link = screen.getByRole( 'link', {
	name: "I'm an anchor link! (opens in a new tab)",
} );

const onClickMock = jest.fn();
link.onclick = onClickMock;

await user.click( link );
expect( onClickMock ).toHaveBeenCalledTimes( 1 );
expect( onClickMock ).toHaveBeenLastCalledWith(
	expect.objectContaining( { defaultPrevented: true } )
);

What do you think?

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 tested this approach, and it is working as expected. I will push new changes so you can review it properly :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, yes I see your point... hard to test the behavior when no onClick is passed by ...passing a mock to onClick 😆

Your proposed solution looks like works, although modifying the event listener imperatively is an unusual pattern. Maybe we just add a brief comment to those two tests explaining that we're using that approach specifically so we can test the defaultPrevented without passing an onClick prop? It's described in the test title, but a comment closer to the actual link.onclick modification might help make it crystal clear for future maintainers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct! 🥲 I just added the comments!

packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/external-link/test/index.tsx Outdated Show resolved Hide resolved
@Initsogar
Copy link
Contributor Author

Thanks @alexstine and @chad1008, I will be working on the suggested changes!

@Initsogar Initsogar requested review from alexstine and chad1008 and removed request for mirka, ajitbohra, ciampo, alexstine and chad1008 October 25, 2022 17:36
@Initsogar
Copy link
Contributor Author

Hmm, I clicked to ask for re-review from @chad1008 and @alexstine and somehow it messed up and removed the other ones that were on the list. Sorry 😅

I just added the changelog entry and made changes on the unit test related to use getByRole and userEvent instead of getByTestId and fireEvent/createEvent. I would appreciate your review :)

@Initsogar Initsogar force-pushed the fix/external-link-onclick-event-handler branch from 3f97de6 to d876017 Compare October 26, 2022 21:34
@Initsogar
Copy link
Contributor Author

@chad1008 I just added some comments for clarification purposes on the approach used for unit testing defaultPrevented on this component while no passing onClick prop. Also resolved the conflict with components CHANGELOG.md.

Copy link
Contributor

@chad1008 chad1008 left a comment

Choose a reason for hiding this comment

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

Looks great @Initsogar, thank you! I left one last inline comment (sorry for not spotting that last time), but after that I think we're good to go 🚀 🚢

Congrats on your first core contribution, btw! 🎉

<ExternalLink
href="#test"
onClick={ onClickMock }
data-testid="external-link"
Copy link
Contributor

Choose a reason for hiding this comment

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

Just noticed this data-testid is still here, but no longer needed. Looks like there's another lingering in the next test as well. We can remove both before merging 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right! Thank you for that!
Just fixed it :)

@Initsogar Initsogar requested a review from chad1008 October 28, 2022 18:55
@Initsogar
Copy link
Contributor Author

@chad1008 @ciampo @mirka Hey there! I pushed the latest suggestion and I think we are ready. Could you confirm and let me know what would be the next step? :) Thanks for all your support!

@ciampo
Copy link
Contributor

ciampo commented Oct 31, 2022

Hey @Initsogar , I re-ran the failing tests (it looks like they're being a flakey lately) and they passed!

I'll go ahead and merge your changes — thank you for helping the project, and congrats on your first contribution 🎉 Happy to collaborate more in the future in case you felt like opening more PRs like this one

@ciampo ciampo merged commit 19186e5 into WordPress:trunk Oct 31, 2022
@github-actions
Copy link

Congratulations on your first merged pull request, @Initsogar! We'd like to credit you for your contribution in the post announcing the next WordPress release, but we can't find a WordPress.org profile associated with your GitHub account. When you have a moment, visit the following URL and click "link your GitHub account" under "GitHub Username" to link your accounts:

https://profiles.wordpress.org/me/profile/edit/

And if you don't have a WordPress.org account, you can create one on this page:

https://login.wordpress.org/register

Kudos!

@github-actions github-actions bot added this to the Gutenberg 14.5 milestone Oct 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Components /packages/components [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Components: ExternalLink onClick event handler is not working
4 participants