Skip to content

Conversation

@lucabezerra
Copy link
Contributor

WHY are these changes introduced?

Modernizes tests to use the new modern framework ({mountWithApp} from test-utilities).

WHAT is this pull request doing?

Updates tests using {mountWithAppProvider} from test-utilities/legacy to use {mountWithApp} from test-utilities

@ghost
Copy link

ghost commented Aug 5, 2021

👋 Thanks for opening your first pull request. A contributor should give feedback soon. If you haven’t already, please check out the contributing guidelines.

it('does not call onClick when hitting keyUp on the item when no URL exists', () => {
const onClick = jest.fn();
const wrapper = mountWithAppProvider(
const wrapper = mountWithApp(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it intentional to have this one test with mockSelectModeContext in the middle of all the other ones with mockDefaultContext?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think so. Feel free to move it out of the default group

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'm wondering if we should move it out of the default group or change it's context to the default one, since the test itself seems related to its neighbours, it's just the context that's different (which could have been some autocomplete mistake). What do you think?


it('renders a checked Checkbox if the item is in the selectedItems context', () => {
const wrapper = mountWithAppProvider(
const wrapper = mountWithApp(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test is in the "SelectMode" describe block, but uses mockSelectableContext. Is this intentional?

@github-actions
Copy link
Contributor

github-actions bot commented Aug 5, 2021

size-limit report

Path Size
cjs 142.51 KB (0%)
esm 96.27 KB (0%)
esnext 139.44 KB (0%)
css 33.74 KB (0%)

@lucabezerra lucabezerra changed the title Switch to using mountWithApp on ResourceItem tests. [Test Modernization] Switch to using mountWithApp on ResourceItem tests. Aug 5, 2021
@lucabezerra lucabezerra force-pushed the resourceitem-modernize-tests branch from 73d04ae to 2bf6d95 Compare August 9, 2021 17:43
@lucabezerra lucabezerra marked this pull request as ready for review August 9, 2021 18:18
@lucabezerra lucabezerra changed the title [Test Modernization] Switch to using mountWithApp on ResourceItem tests. [Test Modernization] Switch to using mountWithApp on ResourceItem and ResourceList tests. Aug 9, 2021
@lucabezerra lucabezerra requested a review from a team August 10, 2021 13:48
Copy link
Member

@kyledurand kyledurand left a comment

Choose a reason for hiding this comment

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

Great job @lucabezerra 👏

);

expect(findByTestID(element, 'Item-Wrapper').prop('data-href')).toBe(url);
const div = element.find('div', {'data-href': url} as any);
Copy link
Member

Choose a reason for hiding this comment

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

You should be able to use toContainReactComponent here

expect(element).toContainReactComponent('div', {'data-href': url});

it('does not call onClick when hitting keyUp on the item when no URL exists', () => {
const onClick = jest.fn();
const wrapper = mountWithAppProvider(
const wrapper = mountWithApp(
Copy link
Member

Choose a reason for hiding this comment

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

I don't think so. Feel free to move it out of the default group

);

expect(item.find('li').prop('data-href')).toBe('google.com');
const li = item.find('li', {'data-href': 'google.com'} as any);
Copy link
Member

Choose a reason for hiding this comment

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

This could probably use toContainReactComponent

);

expect(item.find('li').prop('data-href')).toBeUndefined();
const li = item.find('li', {'data-href': undefined} as any);
Copy link
Member

Choose a reason for hiding this comment

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

Here too

Copy link
Member

@AndrewMusgrave AndrewMusgrave left a comment

Choose a reason for hiding this comment

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

Left a comment about filtering by class names, ideally we wouldn't import the css module & css utilities. We're relying on the implementation logic in the test, which isn't ideal. Other than that, LGTM! 🎉

Comment on lines 390 to 392
styles.ResourceItem,
styles.selectable,
styles.selectMode,
Copy link
Member

Choose a reason for hiding this comment

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

Was there anything we could filter on, other than class names?

Copy link
Member

Choose a reason for hiding this comment

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

I was going to comment on this as well. Importing css modules into our tests will slow them down. Unfortunately we're already doing that in other areas and it is a nicer way to remove findByTestID

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I don't like it either. On top of the reasons you've mentioned, it kinda looks brittle to me (and sometimes complex to figure out which classes are expected depending on which props were passed to the component). I was hoping you folks would be able to suggest me a better alternative. Should I leave it like that, then?

Copy link
Member

@BPScott BPScott Aug 10, 2021

Choose a reason for hiding this comment

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

Slow down will be negligible. The style file is already part of the module graph because ResourceItem itself imports it too. When Jest encounters .scss files it basically maps in identity-obj-proxy which is some very trivial JS that says "any key is valid, return that value as a string" - so styles.ResourceItem is 'ResourceItem', styles.selectable is 'selectable' etc.

Agree with Kyle, that the while not super great it's better than keeping using testID stuff, and I've got no better idea.

To reduce the need to play "guess all the classes' whachamole I think you might be able to use expect.stringContaining to reference just the one

wrapper .find('div', {
  className: expect.stringContaining(styles.ResourceItem)
})!.trigger('onKeyUp', {key: 'Enter'})

e.g.

expect(button).toContainReactComponent(UnstyledButton, {
className: expect.stringContaining('removeUnderline'),
});

or use findWhere to write a filter function if that doesn't work

Copy link
Member

Choose a reason for hiding this comment

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

In addition to Ben's comment, here're a few ideas

  • find('div', {testID}) // we're generally against testID's but thought id mention it still works
  • use the class names directly so we don't reply on implementation logic find('div', {className: 'ResourceItem')
  • extract the logic so it's only in one location
const resourceItemSelector = {className: styles.ResourceItem'}
...
component.find('div', resourceItemSelector)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, everyone!

As @BPScott had anticipated, the expect.stringContaining only works within the context of jest matchers, but I was able to introduce it to a few places anyway. I've used the findWhere everywhere else.

I've also incorporated a bit of @AndrewMusgrave 's suggestion to extract the logic into a single place, hopefully it's looking better now.

Thanks @kyledurand for spotting the places I've missed!

There are now just these 2 points before I can consider this done. Github won't let me paste the direct links to the discussions no matter what I try (it keeps removing the anchor from the link), so please copy the following anchors and paste it at the end of this PR's URL to go straight to them: #discussion_r683666010 and #discussion_r686332281

const ariaLabel = 'View Item';

const resourceItemSelector = {className: styles.ResourceItem};
const resourceItemFilter = (node: any) =>
Copy link
Member

Choose a reason for hiding this comment

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

Having two ways of doing this feels a little strange. It seems like resourceItemFilter does everything resourceItemSelector can but can additional cases. what if we stick with just resourceItemFilter.

I think we can type this better too: node: Node<unknown> where you can do import {Node} from '@shopify/react-testing'. Rathe than import from @shopify/react-testing in this file though, it might be nicer to do import {Node} from 'test-utiilities', and have src/test-utilities/react-testing.tsx rexport the Node type.

@lucabezerra
Copy link
Contributor Author

This has been closed in favor of #4398, which uses the most recent implementation of react-testing, amongst other improvements.

@alex-page alex-page deleted the resourceitem-modernize-tests branch March 22, 2022 04:18
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.

5 participants