Only import the needed plugins in unit tests#66751
Conversation
a311d0a to
bd3338d
Compare
bd3338d to
d005f70
Compare
| }), | ||
| }), | ||
| hasEnterprisePlugins: true, | ||
| specificPlugins: ["collections"], |
There was a problem hiding this comment.
Can you help change existing tests that use a different property name? e.g.
There are 5 of them if you search for "enterprisePlugins: ["
| @@ -21,6 +21,7 @@ const setupEnterprise = (opts: SetupOpts) => { | |||
| }), | |||
| }), | |||
| hasEnterprisePlugins: true, | |||
There was a problem hiding this comment.
Also, I wouldn't mind not changing this as this PR is already huge. But having both flags could be confusing imo as the API isn't quite clear why we need both. I see in the implementation that if hasEnterprise:plugins: true but no specificPlugins, then we import all plugins.
I'd say doing that is unnecessary, as we mostly specify specificPlugins at the setup level, so every test would probably already have to define specificPlugins.
What do you think? Or do you think we really need 2 flags?
| if (hasEnterprisePlugins) { | ||
| setupEnterprisePlugins(); | ||
| if (hasEnterprisePlugins && tokenFeatures?.audit_app) { | ||
| setupEnterpriseOnlyPlugin("audit_app"); |
There was a problem hiding this comment.
This looks in contrast with other tests that accept specificPlugins from the test, not in the setup function. Should we pass specificPlugins instead?
| if (tokenFeatures.audit_app) { | ||
| plugins.push("audit_app"); |
There was a problem hiding this comment.
This looks incorrect. This setup function is used by frontend/src/metabase/dashboard/components/DashboardSettingsSidebar/tests/enterprise.unit.spec.ts which means we're testing enterprise build without proper token features.
And in those tests, we should activate plugins, but don't provide tokenFeatures. And this change will result in enterprise tests not activating the plugins at all.
I haven't take time to check all tests, but I think overall, we should just pass specificPlugins and that parameter alone should dictact what plugin will be activated, not inferring from token features.
3959cf4 to
7250b97
Compare
| function setup(opts: SetupOpts = {}) { | ||
| baseSetup({ | ||
| hasEnterprisePlugins: true, | ||
| enterprisePlugins: "*", // TODO be more granular about this |
There was a problem hiding this comment.
There is some dark magic in this test file, some tests depend on each other. I haven't had the time to investigate this furthermore but that would be a good followup task.
The idea on this file as well as in other ones is to try and be specific about what plugins are required. If that's not possible at the moment, we fallback to using "*" as a way to import all plugins as before.
There was a problem hiding this comment.
I think this is a good compromise 👍 * would all be acceptable, I guess, as we have no standard on how we should name a special value. Or at least, not that I know of.
iethree
left a comment
There was a problem hiding this comment.
Nice work!
My one concern remains that features and plugins don't necessarily map 1:1 and we could get unexpected test behavior. I think we should add a warning about this behavior to the docstring for setupEnterpriseOnlyPlugin so that people are aware of why their tests might not be behaving like they do in the real app. Maybe link to the dependency summary I generated.
e2e tests failed on
|
| File | Test Name |
|---|---|
transforms.cy.spec.ts |
scenarios > admin > transforms > creation > should be possible to create and run a Python transform |
people.cy.spec.js |
scenarios > admin > people > invite member when SSO is configured #23630 |
* Demo of only importing the relevant plugin in unit test * Optimize enterprise plugin unit tests with targeted setupEnterpriseOnlyPlugin calls * fixed tests * fixup * . * fixed test * removed hasEnterprisePlugin * fixup * removed remaining hasEnterprisePlugins and unnecessary setupEnterprise fn * specificPlugins -> enterprisePlugins * . * fixed type * docs
|
@lorem--ipsum Manual conflict resolution is required on #67248 |
| @@ -18,7 +18,7 @@ import { createMockTokenFeatures } from "metabase-types/api/mocks"; | |||
|
|
|||
| function setup(opts: SetupOpts = {}) { | |||
| baseSetup({ | |||
There was a problem hiding this comment.
Consider specifying the exact plugins needed instead of using "*" for better test performance and clarity about dependencies.
| entity_id: createMockEntityId("okNLSZKdSxaoG58JSQY54"), | ||
| }, | ||
| hasEnterprisePlugins: true, | ||
| enterprisePlugins: "*" as const, // TODO: specify exact plugins needed |
There was a problem hiding this comment.
Consider specifying the exact plugins needed instead of using "*" for better test performance and clarity about dependencies.
| can_write: false, | ||
| }, | ||
| hasEnterprisePlugins: true, | ||
| enterprisePlugins: ["audit_app" as const, "collections" as const], |
There was a problem hiding this comment.
Style inconsistency: The as const type assertion is used here but not in the vast majority of other enterprisePlugins arrays throughout this PR (only 3 out of 101 usages). Consider removing as const from the array elements for consistency, unless there's a specific type narrowing requirement here that's not present elsewhere.
TypeScript/JavaScript Code ReviewI've reviewed the TypeScript/JavaScript changes in this PR for compliance with coding standards. The changes generally follow good patterns with consistent interface definitions and proper type usage. Issues Found:
Positive Observations:
The changes align with the PR's goal of improving test performance through targeted plugin imports. |
* Demo of only importing the relevant plugin in unit test * Optimize enterprise plugin unit tests with targeted setupEnterpriseOnlyPlugin calls * fixed tests * fixup * . * fixed test * removed hasEnterprisePlugin * fixup * removed remaining hasEnterprisePlugins and unnecessary setupEnterprise fn * specificPlugins -> enterprisePlugins * . * fixed type * docs Co-authored-by: Sébastien <sebastien@metabase.com>
|
@lorem--ipsum Something went wrong while creating backport [Logs] |
It's okay, I just updated the label for precision but the backport has already been made and merged (which is why the action failed — there was nothing to commit). |
| function setup(opts: SetupOpts = {}) { | ||
| baseSetup({ | ||
| hasEnterprisePlugins: true, | ||
| enterprisePlugins: "*", // TODO be more granular about this |
There was a problem hiding this comment.
I think this is a good compromise 👍 * would all be acceptable, I guess, as we have no standard on how we should name a special value. Or at least, not that I know of.
|
|
||
| function setup(opts: SetupOpts) { | ||
| baseSetup({ hasEnterprisePlugins: true, ...opts }); | ||
| baseSetup({ ...opts }); |
There was a problem hiding this comment.
Not sure if this is correct. What I think should happen in this PR is either one of the following modifications.
- removing
hasEnterprisePlugins: trueand replacing it with one or more plugins - removing
hasEnterprisePlugins: trueand replacing it with* - removing
hasEnterprisePlugins: falseand doing nothing as we won't be activating any plugins if not passingenterprisePlugins
This however, removes hasEnterprisePlugins: true, meaning that it won't test the case where the plugin is activated anymore it will just look like common.* test. As a reminder, enterprise.* test should test the situation where plugins are activated, but no appropriate token features are provided, so the features shouldn't be available.
| enterprisePlugins.forEach((plugin) => { | ||
| setupEnterpriseOnlyPlugin(plugin); | ||
| }); |
There was a problem hiding this comment.
This is exactly what I think looks the cleanest. I just read through another variable where there's a check for the existence of enterprisePlugins. They could looks like this for consistency too.
|
|
||
| function setup(opts: SetupOpts) { | ||
| return baseSetup({ | ||
| hasEnterprisePlugins: true, |
There was a problem hiding this comment.
Here's another enterprise test that has no plugins activated. I think it should either be enterprisePlugins: ["somefeature"] or enterprisePlugins: "*"
|
|
||
| function setup(opts: SetupOpts) { | ||
| baseSetup({ | ||
| hasEnterprisePlugins: true, |
There was a problem hiding this comment.
one thing I can say is that the enterprise tests should have the same set of plugins as the premium tests. So in this case we should add enterprisePlugins: ["whitelabel"], but not passing the tokenFeatures.
This would apply to all enterprise test that has hasEnterprisePlugins: true, removed without adding enterprisePlugins as I might not be able to cover all of them.
| const setup = async ({ isAdmin = true, initialRoute = "" } = {}) => { | ||
| return baseSetup({ | ||
| hasEnterprisePlugins: false, | ||
| enterprisePlugins: undefined, |
There was a problem hiding this comment.
saw other tests just casually drop hasEnterprisePlugins: false, maybe it's fine not to pass enterprisePlugins at all?
| ...opts, | ||
| }); | ||
| } | ||
| import { setup } from "./setup"; |
There was a problem hiding this comment.
there should be plugin initialization on enterprise tests.
| entity_id: createMockEntityId("okNLSZKdSxaoG58JSQY54"), | ||
| }, | ||
| hasEnterprisePlugins: true, | ||
| enterprisePlugins: "*" as const, // TODO: specify exact plugins needed |
There was a problem hiding this comment.
Please always provide dates on all todo comments. Ref
In this PR, bulk
setupEnterprisePluginscalls are replaced with more targeted calls tosetupEnterpriseOnlyPlugin.This demonstrates and quantifies how importing specific plugins in unit tests improves performance, but also really helps understanding what depends on which plugins.
Before:
After:
Command executed through a loop: