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

[makeId] Makes it difficult for consumers to create Jest tests #1381

Closed
cjcenizal opened this issue Dec 18, 2018 · 10 comments · Fixed by #4212
Closed

[makeId] Makes it difficult for consumers to create Jest tests #1381

cjcenizal opened this issue Dec 18, 2018 · 10 comments · Fixed by #4212

Comments

@cjcenizal
Copy link
Contributor

cjcenizal commented Dec 18, 2018

(edit: see this comment below for how to solve this for makeId and htmlIdGenerator)

Any component which consumes makeId or a similar dynamic ID-generator will create non-deterministic IDs every time it's instantiated (e.g. EuiDescribedFormGroup, EuiFormRow, EuiToolTip). This is problematic for consumers who want to create jest tests for any UI which is built with these components. EUI solves this problem by mocking makeId in its own unit tests, but this isn't an option for consumers.

Maybe we could we use an environment variable to make makeId return a stub value?

@chandlerprall
Copy link
Contributor

If it's a global solution, such as an environment variable, I think it'd make sense to have the random generators return a hard-coded answer so test execution order doesn't affect it. However, this breaks the idea that an id is unique, though I find it unlikely there's a valid reason for a test to care about any of these random ids.

The other way I'd go is expose a mocking function through the module itself and then the consumer can decide if they want to mock at a global level (Jest setup), per suite, or even per test.

The global mock via flag sounds easiest and nicest for the consumer, as long as having duplicate generated ids is fine. Thoughts?

@cjcenizal
Copy link
Contributor Author

cjcenizal commented Dec 19, 2018

The only situation in which I can imagine the id mattering to a test would be one in which we're mounting the component and doing some heavy interaction with it, e.g. clicking on a label in order to give focus to an input. But this seems pretty far-fetched since it's arguably beyond the realm of unit testing.

The global mock via flag sounds easiest and nicest for the consumer, as long as having duplicate generated ids is fine.

Let's give it a whirl! My only suggestion would be to name the flag something super specific and scoped to EUI, e.g. euiMockedGeneratedIds.

@sebelga
Copy link
Contributor

sebelga commented Dec 26, 2018

I managed to get a deterministic ID by simply adding this line add the top of the test file

jest.mock('@elastic/eui/lib/components/form/form_row/make_id', () => () => 'my-id');

I think it's a good enough solution and I don't think our unit tests need the aria ids for anything.

The only thing that is strange to me is why the makeId() utility function is under form, when it is used by many other components.

@chandlerprall
Copy link
Contributor

While it is certainly possible for Kibana tests to mock the implementation, I don't think EUI should rely on the functionality, nor force consuming applications into considering EUI's internals when writing tests. However, it does make addressing this lower priority - and thank you for providing the code necessary to work around the issue!

@cjcenizal
Copy link
Contributor Author

If we implement the global mock flag, then we could also update components which use portals (e.g. EuiOverlayMask, EuiPortal) to conditionally render their children when the flag is set to true, instead of creating a portal. This would make it easier for unit tests to find modals and things. This would expand the responsibility/meaning of the global mock flag, so maybe naming it something like "EUI test mode" would make more sense.

  render() {
    if (IS_EUI_TEST_MODE) {
      return this.props.children;
    }

    return createPortal(
      this.props.children,
      this.portalNode
    );
  }

@chandlerprall
Copy link
Contributor

FWIW, latest versions of enzyme support portals (and Kibana does as of last week); we should be upgrading Enzyme in EUI soon(ish).

@cjcenizal
Copy link
Contributor Author

@chandlerprall Great point! Thanks, I take back my comment. :)

@BentoumiTech
Copy link

It seems that now we need to mock htmlIdGenerator since #3129

jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
  htmlIdGenerator: () => () => 'htmlId',
}));

It's also mocked inside the codebase for snapshot testing

jest.mock('../../services/accessibility/html_id_generator', () => ({

@chandlerprall
Copy link
Contributor

We now have a test-env build (docs) which we should create an auto-mock for the htmlIdGenerator. Interestingly, I think this can be done without affecting any applications' existing jest mocks for htmlIdGenerator as they'd still be targeting the same file(s).

@chandlerprall
Copy link
Contributor

Extending the above thought on including a testenv version of htmlIdGenerator: we could hash the stack trace - maybe removing the line numbers - to generate a consistent, yet unique, ID.

@cchaos cchaos changed the title makeId makes it difficult for consumers to create Jest tests [makeId] Makes it difficult for consumers to create Jest tests Sep 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants