[Uptime] Tests/uptime testing utils#87650
Conversation
|
Pinging @elastic/uptime (Team:uptime) |
40be0cd to
afea632
Compare
| ); | ||
| }; | ||
|
|
||
| export const renderTLWithRouter = ( |
There was a problem hiding this comment.
my initial though is that, imo, i don't think we should name it like this renderWithRouter or renderWithKibana stuff.
I wish we can find a better naming? maybe just have it as simple render, and by default we should add kibana, router and redux for all components, since most components in uptime are dependent those.
I don't think we will have a use case where adding those by default will cause problems.
There was a problem hiding this comment.
The one reason I didn't name it renderWithRouter is because we already have a renderWithRouter in this same file that we are using for enzyme.
I will consider consolidating into one render function.
There was a problem hiding this comment.
This is an example where we needed to extend the core options. You can do so by passing customCoreOptions. If you need to overwrite the entire core and make your own mock, you can do so by passing { kibanaProps: { services: { ...myCustomCore } } }.
There was a problem hiding this comment.
I'm unable to figure out why this component needed to call getEditAlertFlyout. The MLJobLink component sets up an href and a few other fields and renders a link.
There was a problem hiding this comment.
This is an example of overwriting the entire Kibana context core. This is useful in this context to get access to a function for getting the breadcrumbs out of core.
There was a problem hiding this comment.
I wanted to create a mock core that met most of our use cases without having to add to it, but I don't have the context to know what that looks like. I would love feedback here.
There was a problem hiding this comment.
TBH this might be something we need to take a couple of attempts at and incrementally improve it as we run into different issues. I think we can try to review the fields we use to a certain extent but it's ok if we need to revisit the default mock.
There was a problem hiding this comment.
I'm not sure what the types should be for some of these pieces. I welcome feedback here.
There was a problem hiding this comment.
let's remove the custom prefix, i think that's unnecessary
There was a problem hiding this comment.
Regarding the types, I believe Kibana Core team exports types for core that we can use here. See https://github.com/elastic/kibana/blob/master/x-pack/plugins/uptime/public/apps/plugin.ts#L7
cc @shahzad31 does that sound right?
There was a problem hiding this comment.
i think there might be a kibana core mock as well exported by team, may be use that directly?
There was a problem hiding this comment.
i have seen that somewhere
There was a problem hiding this comment.
@dominiqueclarke might be worth asking in #kibana-developer-experience channel
| } | ||
| ); | ||
| expect(wrapper).toMatchSnapshot(); | ||
| expect(asFragment()).toMatchSnapshot(); |
There was a problem hiding this comment.
I only changes this to useasFragment because I don't have further context about this component to know how to test it without a snapshot. I'm using it as an example for now.
There was a problem hiding this comment.
I think we can improve this even more and remove the need for asFragment.
What do you think of 9728d3a? We're essentially testing the user-facing features of the component; specifically we ensure our text is displayed and the href we build is what we expect. As a bonus we can eliminate the snapshot file altogether.
There was a problem hiding this comment.
I think that's perfect. I wasn't sure how to format that full url lol.
| customCoreOptions, | ||
| kibanaProps, | ||
| }: { | ||
| children: ReactElement; |
There was a problem hiding this comment.
Are you planning to define an interface rather than specifying the types inline like this? These Mock functions have a lot of parameter overlap.
There was a problem hiding this comment.
TBH this might be something we need to take a couple of attempts at and incrementally improve it as we run into different issues. I think we can try to review the fields we use to a certain extent but it's ok if we need to revisit the default mock.
| <ExecutedStep index={3} step={step} checkGroup={'fake-group'} /> | ||
| ); | ||
|
|
||
| expect(getByText(`${step?.synthetics?.step?.index}. ${step?.synthetics?.step?.name}`)); |
There was a problem hiding this comment.
This is exactly what I was hoping to achieve when we talked about this test. It tests the same thing in a much cleaner format.
| import { mountWithRouter, renderTLWithRouter } from '../../../lib'; | ||
|
|
||
| // FLAKY: https://github.com/elastic/kibana/issues/85899 | ||
| describe.skip('ExecutedStep', () => { |
There was a problem hiding this comment.
We might want to cherry-pick this change to a separate branch and revert it here, since we're going to need to get approval to close the issue before we can remove the skip. I'm fine with keeping the test revision below since they're all skipped in master right now anyway.
There was a problem hiding this comment.
Regarding the types, I believe Kibana Core team exports types for core that we can use here. See https://github.com/elastic/kibana/blob/master/x-pack/plugins/uptime/public/apps/plugin.ts#L7
cc @shahzad31 does that sound right?
6182468 to
48f1536
Compare
|
@elasticmachine merge upstream |
justinkambic
left a comment
There was a problem hiding this comment.
This is looking great, and I've already merged these commits into some other testing that I'm doing and everything went well. I had a few recommendations on typings etc, and some possible improvements to one of the example tests we're touching here.
I checked out this code and made two commits, 9728d3a and 8e35b6b. They summarize most of my revision comments below. Ping with any follow-up.
Thanks for taking this on, it's going to be a big help going forward!
| } | ||
|
|
||
| export function withRouter<T>(WrappedComponent: React.ComponentType<T>, customHistory: History) { | ||
| const history = customHistory || createMemoryHistory(); |
There was a problem hiding this comment.
It seems like customHistory should be optional since we have a default if it is falsey.
| } | ||
| ); | ||
| expect(wrapper).toMatchSnapshot(); | ||
| expect(asFragment()).toMatchSnapshot(); |
There was a problem hiding this comment.
I think we can improve this even more and remove the need for asFragment.
What do you think of 9728d3a? We're essentially testing the user-facing features of the component; specifically we ensure our text is displayed and the href we build is what we expect. As a bonus we can eliminate the snapshot file altogether.
| import React from 'react'; | ||
| import { coreMock } from 'src/core/public/mocks'; | ||
| import { renderWithRouter, shallowWithRouter } from '../../../lib'; | ||
| import { render } from '../../../lib'; |
There was a problem hiding this comment.
One thing I noticed in practice when testing this out was my editor had some issue loading the typings for this function. Is this happening for you? When I edited the path to do a direct import it worked. I can't figure out why this would be a code-related problem, but I'm curious if it's happening with others.
Specifically, I didn't get any intellisense in VS Code for the asFragment function returned by render.
We've had some issues with these types of import chains in the past. Not saying we should mandate always doing direct imports for this helper, but it might be helpful for some.
| ); | ||
| } | ||
|
|
||
| export function withRouter<T>(WrappedComponent: React.ComponentType<T>, customHistory: History) { |
There was a problem hiding this comment.
It might be good to seek out a test where this HoC can be used and provide an example. I think right now it returns JSX.Element, if we're intending for it to be passed to RTL render directly we might want to make sure the inferred return type is ReactElement. If someone finds this HoC it would be ideal for them to Find all references and see it in action somewhere in the codebase, IMO.
In any case, I think it's rare that we'll need to call this specifically, as the custom render you've created below should cover the vast majority of use cases and is simpler to interface with.
There was a problem hiding this comment.
My original idea of using HOCs was a bit misguided, but I left them here in case they are helpful for anyone in any other contexts.
I used to work with RTL using HOCs. I would first create the wrapped component (JSX.Element), and then pass the ReactElement to RTL like so
const WrappedComponent = withRouter(Component, history);
render(<WrappedComponent {...props} />);
But that just creates one more unnecessary step.
All in all I think these can be removed.
There was a problem hiding this comment.
Ah I see; I'm inclined to agree if we don't have a need for them today. If we run into an instance where using HOCs is preferable, it seems like it will be a small implementation effort to re-add them.
| ui: ReactElement, | ||
| { history, coreOptions, kibanaProps, renderOptions, state }: RenderRouterOptions = {} | ||
| ) => { | ||
| return reactRender( |
There was a problem hiding this comment.
Maybe we should alias this as reactTestRender to denote it's calling render imported from RTL and not react-dom.
I think if the reader understands the context of this file it's probably not necessary, but some more descriptive name like that (or a better suggestion) might improve readability.
There was a problem hiding this comment.
Maybe we should name it something other than reactTestRender since react test renderer is a thing that it may be confused with. How about reactTestLibRender
There was a problem hiding this comment.
That sounds fine to me. This way it will disambiguate the source of the function for the person reading the code.
| } | ||
|
|
||
| interface KibanaProviderOptions { | ||
| coreOptions?: any; |
There was a problem hiding this comment.
Are we able to reference CoreStart here? As I understand it we use this field to let people supply their own coreOptions, which we spread overtop of the default mock we create. So could we type this as Partial<CoreStart>, so the caller could supply just one or two fields if needed, or a full mock if they wanted?
| coreOptions?: any; | |
| coreOptions?: Partial<CoreStart>; |
| interface RenderRouterOptions extends KibanaProviderOptions { | ||
| history?: History; | ||
| renderOptions?: any; | ||
| state?: any; |
There was a problem hiding this comment.
| state?: any; | |
| state?: AppState; |
There was a problem hiding this comment.
The one thing I don't love about requiring the full app state, is that you have to provide pieces of state that are unnecessary to the particular component you are testing in order to satisfy the interface.
There was a problem hiding this comment.
Maybe we could use generics for this and specify the smaller slice of state you need.
There was a problem hiding this comment.
Good point; can we use Partial<AppState> instead, and when we
<MountWithReduxProvider store={store}>change it to:
<MountWithReduxProvider store={...mockStore, ...userStore}>|
|
||
| interface RenderRouterOptions extends KibanaProviderOptions { | ||
| history?: History; | ||
| renderOptions?: any; |
There was a problem hiding this comment.
I think we should require a type of Omit<RenderOptions, 'queries'>, mimicking the render function that RTL exports.
| renderOptions?: any; | |
| renderOptions?: Omit<RenderOptions, 'queries'>; |
| const { asFragment } = render( | ||
| <MLJobLink dateRange={{ to: '', from: '' }} basePath="" monitorId="testMonitor" />, | ||
| { | ||
| coreOptions: { triggersActionsUi: { getEditAlertFlyout: jest.fn() } }, |
There was a problem hiding this comment.
| coreOptions: { triggersActionsUi: { getEditAlertFlyout: jest.fn() } }, |
I think the test will succeed without this when we migrate to RTL. See revision in 8e35b6b.
There was a problem hiding this comment.
I'm unable to figure out why this component needed to call getEditAlertFlyout. The MLJobLink component sets up an href and a few other fields and renders a link.
dominiqueclarke
left a comment
There was a problem hiding this comment.
Thanks for the feedback! One note about AppState, I'd love to get around requiring the full AppState for redux tests if possible.
| } | ||
| ); | ||
| expect(wrapper).toMatchSnapshot(); | ||
| expect(asFragment()).toMatchSnapshot(); |
There was a problem hiding this comment.
I think that's perfect. I wasn't sure how to format that full url lol.
| interface RenderRouterOptions extends KibanaProviderOptions { | ||
| history?: History; | ||
| renderOptions?: any; | ||
| state?: any; |
There was a problem hiding this comment.
The one thing I don't love about requiring the full app state, is that you have to provide pieces of state that are unnecessary to the particular component you are testing in order to satisfy the interface.
| ); | ||
| } | ||
|
|
||
| export function withRouter<T>(WrappedComponent: React.ComponentType<T>, customHistory: History) { |
There was a problem hiding this comment.
My original idea of using HOCs was a bit misguided, but I left them here in case they are helpful for anyone in any other contexts.
I used to work with RTL using HOCs. I would first create the wrapped component (JSX.Element), and then pass the ReactElement to RTL like so
const WrappedComponent = withRouter(Component, history);
render(<WrappedComponent {...props} />);
But that just creates one more unnecessary step.
All in all I think these can be removed.
| ); | ||
| }; | ||
|
|
||
| /* Enzyme helpers */ |
There was a problem hiding this comment.
They are copied.
…iqueclarke/kibana into tests/uptime-testing-utils
fe5c729 to
ae7406b
Compare
|
|
||
| export { MountWithReduxProvider } from './helper'; | ||
| export * from './helper/helper_with_router'; | ||
| export * from './helper/enzyme_helpers'; |
There was a problem hiding this comment.
Exported the enzyme helpers from here in order to maintain compatibility with the existing tests without having to change the imports.
💚 Build SucceededMetrics [docs]
History
To update your PR or re-run it, just comment with: |
* add additional component test helpers * add test examples * uptime testing utils remove custom prefix from props and parameter options * skip executed step tests * adjust MlJobLink test * add testing util interfaces * update mock core * combine wrappers into one custom render function * split enzyme helpers and rtl helpers into different files and adjust types * adjust types * spread core on render function * remove unnecessary items from MLJobLink test * update use_monitor_breadcrumbs test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
* add additional component test helpers * add test examples * uptime testing utils remove custom prefix from props and parameter options * skip executed step tests * adjust MlJobLink test * add testing util interfaces * update mock core * combine wrappers into one custom render function * split enzyme helpers and rtl helpers into different files and adjust types * adjust types * spread core on render function * remove unnecessary items from MLJobLink test * update use_monitor_breadcrumbs test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
* add additional component test helpers * add test examples * uptime testing utils remove custom prefix from props and parameter options * skip executed step tests * adjust MlJobLink test * add testing util interfaces * update mock core * combine wrappers into one custom render function * split enzyme helpers and rtl helpers into different files and adjust types * adjust types * spread core on render function * remove unnecessary items from MLJobLink test * update use_monitor_breadcrumbs test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
* add additional component test helpers * add test examples * uptime testing utils remove custom prefix from props and parameter options * skip executed step tests * adjust MlJobLink test * add testing util interfaces * update mock core * combine wrappers into one custom render function * split enzyme helpers and rtl helpers into different files and adjust types * adjust types * spread core on render function * remove unnecessary items from MLJobLink test * update use_monitor_breadcrumbs test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Summary
Fixes #87419
Adds testing additional testing utilities
Mock Provider Components
React testing library custom renders
renderTLWithKibana - a render function that takes a React Element and renders it using react testing library, wrapped in KibanaContextProvider and 118nProvider
renderTLWithRouter - a render function that takes a React Element and renders it using react testing library, wrapped in Router, in addition to KibanaContextProvider and 118nProvider
The idea is that if you don't need a router, you can use one of the Kibana only mock components or custom renders. The assumption is made that if you need a router, you probably need the KibanaContextProvider as well.
Some tests were changed as examples.