-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Enterprise Search] Automatically mock shared logic files #88494
Conversation
- Caused by leaking auto mocks - work around this by importing from files directly and not from index.ts - Also clean up / use new auto mocks (e.g. for kibana) - Convert old instances of useValues mock to setMockValues
+ move LogicMounter and destructured mock values to top of describe block
+ udpate to use new clearFlashMessages helper
+ update to use LogicMounter
+ update to use new clearFlashMessages helper
+ update to use new flash message helpers
+ consolidate mocks imports
- all jest.mocks come along from the ride when the __mocks__ folder is imported, so HttpLogic is now automatically already mocked
describe('AnalyticsLogic', () => { | ||
const { mount } = new LogicMounter(AnalyticsLogic); | ||
const { history } = mockKibanaValues; | ||
const { http } = mockHttpValues; | ||
const { flashAPIErrors } = mockFlashMessageHelpers; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to reorganize our tests a bit in the light of all these new fancy helpers. Here's the basic architecture I'm thinking:
/**
* License header
*/
// Mocks go here
import { LogicMounter, mockHttpValues } from '../../__mocks__';
// 3rd party imports go here
import React from 'react';
import { shallow } from 'enzyme';
// 1st party shared/lib/helper imports go here
import { someHelper } from '../../../shared/helper';
// 1st party specific imports go here
import { SomeComponent } from '../';
import { SomeLogic } from './';
describe('SomeLogic', () => {
// Destructuring from mocks go here - e.g., `mount` from LogicMounter
const { mount, unmount } = new LogicMounter(SomeLogic);
const { http } = mockHttpValues;
// Constants (e.g.) values, actions go here
const DEFAULT_VALUES = { ... };
const foo = 'bar';
// Jest before/after/all blocks
beforeEach(() => {
// ...
});
// Start the tests
it('does something', () => {});
});
LMK what you think!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this, let's make sure it's in a README file somewhere in this codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm you think so? Maybe I'm overly optimistic, but I'm hoping that we follow this by osmosis - I figure someone opening the codebase for the first time will be like "Oh all the unit tests are written this way, I'll just follow it/copy this file".
My only hesitation with putting this in our README is if it falls out of date, etc. That being said there's definitely a testing section in our main README, so if other folks are +1 to this I can definitely add it there!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree with ya there constance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. I left a non-blocking comment about the value of allowing the import { mockKibanaValues, mockHttpValues, mockFlashMessageHelpers } from '../../../__mocks__';
style import compared to the cost of debugging its side-effects in the future. Even if we decide to go in that direction we can handle it in a follow-up PR, it does not need to block the work already done here to improve our tests.
export { | ||
mockFlashMessagesValues, | ||
mockFlashMessagesActions, | ||
mockFlashMessageHelpers, | ||
} from './flash_messages_logic.mock'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never really understood the value of creating these kinds of index.ts
files for bundling unrelated code in sub-directories. That this introduces side-effects (if you import anything from this file everything gets mocked) seems REALLY weird, and is not something I would expect to encounter, and I imagine would be gnarly to debug. You mention a solution is to import these mocks individually in files, which you do for a couple of tests. Maybe we should handle all mock imports that way? Is there an upside to this I'm not seeing that's worth the side-effect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya it's definitely an architectural decision. As with everything it's all about dev tradeoffs, in my personal opinion I do strongly feel that it's nice to not have to dive deeply into folders - when I'm outside that folder but reaching into it from another component, it's very nice to just have everything available from the top-level index.ts
file and not to have 3 different lines of imports for 3 different files.
It's also one that Kibana uses everywhere (example file) so I personally feel confident following them in this area. Should they ever change this (which I imagine would primarily be due to performance reasons, tree shaking, etc.), I would definitely be +1 to following suit.
I will also note that the side effects are limited to tests/jest.mock()
behavior, whereas the benefits of quicker and combined imports apply outside those and to our source code as well (the main benefit IMO). For me at least the cost is well worth it once imports are understood - they were only unexpected to me because I didn't really understand how they worked. I strongly also think we'll find any side effects do not negatively impact like 95+% of our final code base.
describe('AnalyticsLogic', () => { | ||
const { mount } = new LogicMounter(AnalyticsLogic); | ||
const { history } = mockKibanaValues; | ||
const { http } = mockHttpValues; | ||
const { flashAPIErrors } = mockFlashMessageHelpers; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this, let's make sure it's in a README file somewhere in this codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fantastic! Always great to see my personal todos done in someone else's PR 😂
Thanks Constance!
So clean and nice. 100 ✋ high-five. |
Thanks y'all! I'll go ahead and merge this for now without a README update, but if y'all would like one, def feel free to open a PR or bug me about it later as a follow-up PR! |
…88530) * Update shared logic mocks to automatically mock their exports * Update FlashMessages to also mock its helper fns * Fix tests that were relying on component exports from shared logic files * Fix broken flash_messages tests - Caused by leaking auto mocks - work around this by importing from files directly and not from index.ts - Also clean up / use new auto mocks (e.g. for kibana) - Convert old instances of useValues mock to setMockValues * [AS] Update AnalyticsLogic test to use new auto mockers + move LogicMounter and destructured mock values to top of describe block * [AS] Update CredentialsLogic + udpate to use new clearFlashMessages helper * [AS] Update documents logic tests * [AS] Update engines logic tests * [AS] Update log retention logic test * [Shared] Update IndexingStatus tests + update to use LogicMounter * [Shared] Update telemetry logic test * [WS] Update AddSourceLogic + update to use new clearFlashMessages helper * [WS] Update groups logic files + update to use new flash message helpers * [WS] Update OverviewLogic test * [WS] Update AddSource component test + consolidate mocks imports * [Shared] Clean up KibanaLogic imports - all jest.mocks come along from the ride when the __mocks__ folder is imported, so HttpLogic is now automatically already mocked * [AS] Update EngineRouter test # Conflicts: # x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.test.tsx # x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts # x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.ts
* master: (33 commits) [Security Solution][Case] Fix patch cases integration test with alerts (elastic#88311) [Security Solutions][Detection Engine] Removes duplicate API calls (elastic#88420) Fix log msg (elastic#88370) [Test] Add tag cloud visualization to dashboard in functional test for reporting (elastic#87600) removing kibana-core-ui from codeowners (elastic#88111) [Alerting] Migrate Event Log plugin to TS project references (elastic#81557) [Maps] fix zooming while drawing shape filter logs errors in console (elastic#88413) Porting fixes 1 (elastic#88477) [APM] Explicitly set environment for cross-service links (elastic#87481) chore(NA): remove mocha junit ci integrations (elastic#88129) [APM] Only display relevant sections for rum agent in service overview (elastic#88410) [Enterprise Search] Automatically mock shared logic files (elastic#88494) [APM] Disable Create custom link button on Transaction details page for read-only users [Docs] clean-up vega map reference documenation (elastic#88487) [Security Solution] Fix Timeline event details layout (elastic#88377) Change DELETE to POST for _bulk_delete to avoid incompatibility issues (elastic#87914) [Monitoring] Change cloud messaging on no data page (elastic#88375) [Uptime] clear ping state when PingList component in unmounted (elastic#88321) [APM] Consistent terminology for latency and throughput (elastic#88452) fix copy (elastic#88481) ...
* Initial copy/paste of component tree Only does linting changes and lodash import * Replace withRouter HOC with hooks Use useLocation and no longer pass around history, using the KibanaLogic navigateToUrl method instead * Migrate LicenseCallout component * Update paths Also change name of component to OauthApplication as the default import was named that before * Remove conditional and passed in flash messages This is no longer needed with the Kibana syntax. Flash messages are set globally and only render when present. * Replace removed ConfirmModal In Kibana, we use the Eui components directly * Use internal tools for determining license * Fix a bunch of type issues * Remove telemetry settings section We no longer control telemetry in Workplace Search. It is handled by Kibana itself * Add SettingsSubNav component * Add route and update nav * Remove legacy AppView and sidenav * Clear flash messages globally * Remove global name change method call The global org name is not used anywhere outside of this section so we no longer need to update the global organization object as it is re-fetched when this section is entered. Previously, we displayed the org name in the sidebar but that has been removed in Kibana * Refactor saveUpdatedConfig We recently split out the logic from SourceLogic to the new AddSourceLogic and in settings, we were calling the saveSourceConfig method from the SourceLogic (now in AddSourceLogic) file and passing a callback that set the flash messages from that component’s state. Now, we set the flash messages globally and no longer need to have a saveUpdatedConfig method in the logic file, but can call it directly in the component and the flash messages will be set globally. * Update logic file to use global flash messages * Update server routes * Replace Rails http with kibana http * Fix subnav * Update routes to use consistent syntax We use this method across both Enterprise Search products in Kibana * Shorten nav item copy This would be the only place in the sidebar with a nav item breaking to a second line. * Fix some random typos * Replace React Router Link with helper * Add i18n * Remove redundant clearing of flash messages This happens automatically now in the global flash messages logic; route changes trigger clearing of messages * Add unit tests for components * Add tests for router * Store oauthApplication in mock for reuse * Add tests for SettingsLogic * Fix typo * Remove unncessary imports Copied from this PR: #88525 * Refactor to use new helpers when mocking See #88494 * Update logic test to use error helper See #88422 * Fix type issue * Fix whitespace lint issue Co-authored-by: Kibana Machine <[email protected]>
Summary
Part 2 of my Jest cleanup: I've mentioned recently after seeing a ton of
jest.mock('../../../shared/kibana')
(orhttp
, orflash_messages
, etc.) cruft at the top of our logic files that it would be really nice to clean up / DRY out said mocks. We already do this for our React component tests via mockinguseValues
anduseActions
, but we didn't have this for our actual Kea logic tests that directly connected/grabbed values from other files (e.g.SomeLogic.value.someValue
).Well, I was yesterday years old when I learned that jest.mock() is relative to the test file, not to the actual file being tested... meaning that we can definitely DRY out mocking our logic. I decided to accomplish this by directly mocking each shared logic file in its
__mocks__/*_logic.mock.ts
(see 93b7242). This means that importing any mocks from our__mocks__
folder will automatically mock the logic file for you. Check out the following code diff example:becomes:
The latter is hopefully much cleaner and nicer to use - we shouldn't have to manually mock
XLogic.values
orYLogic.actions
in the future, we just have to pull the existing mocked actions/values from our mock helpers. 🎉Following along
I recommend following this PR by-commit since it touches so many different files.
A warning about this approach
It's a fairly "hungry" change. I wasn't super familiar with how imports worked previously (I thought you had to statically import the entire file to get the
jest.mock()
functionality), but I'm definitely more familiar now. So here's the warning:__mocks__
index folder, you are now automatically importing all the mocks for every single one of these shared logic files.For the most part, this shouldn't be a huge deal. Mocks are a way of life in unit testing unless we are attempting to unit test the logic file itself, in which case we have a few options:
__mocks__
, e.g. import specifically__mocks__/http_logic.mock
which still retains the Kibana logic file as-is for example.__mocks__
, but retain importing the actual file by importing from the*_logic.ts
file directly - e.g.,import { HttpLogic } from 'shared/http/http_logic
instead ofshared/http
(since our mocks are mocking theindex.ts
obj, not the actual files).See b49b877 as an example of the folder most affected by this hungry mocking - because some of these files do require pulling from the
__mocks__
folder to mock other logic/kea/etc, I had to change all test files to import the code they were testing directly from their source files to fix the tests.Again, to reiterate, this should mostly only affect shared logic files, and I don't anticipate us adding a whole lot more of those. I think the tradeoff there (some extra consideration) vs 90% of the rest of the app gaining nicer dev QOL is worth it.
Checklist