Skip to content

Conversation

@oleggromov
Copy link
Contributor

@oleggromov oleggromov commented Nov 29, 2023

Fixes #35503

Description

The problem was that for some reason in Dashboard.componentDidUpdate, the method that decides whether to fetch new data, only parameter values where checked — but not parameters themselves.

I have fixed that, removing garbage code along the way, and added "unit tests" for the Dashboard component. Net change (without the test code) is -46 sloc, which I think is worth it.

Test approach evolution

  1. I have tried to implement an e2e test suite, which is pure madness in my opinion — I would've to recreate the entire page in a browser and click through 10 times to cover a tiny conditional way down in the function call tree.
  2. Then I tried to extract a real unit from a react component (which hardly is a "unit" itself), but realised that I would still need to invoke the component itself to make sure the integration of the component and this unit with conditionals is covered too.
  3. Finally I have found a happy middle ground, which I am quite satisfied with, but the setup part is ugly anyways.

PS Certainly the tests we produce with react testing library aren't unit tests because they require a rich environment, so much mocking, and are slow.

How to verify

Repeat after what I do in the screencast.

Before it didn't work

287385786-a0544210-58b4-486f-95ca-c81d8b26e5e8.mov

Now it works

287386102-4a8010f3-09e5-4660-b07e-09076d263189.mov

Checklist

  • Tests have been added/updated to cover changes in this PR

@oleggromov oleggromov added the backport Automatically create PR on current release branch on merge label Nov 30, 2023
@oleggromov oleggromov added this to the 0.47.9 milestone Nov 30, 2023
@oleggromov oleggromov force-pushed the bugfix-35503-new branch 2 times, most recently from 8661ca2 to 25dc512 Compare November 30, 2023 18:42
@deploysentinel
Copy link

deploysentinel bot commented Nov 30, 2023

No failed tests 🎉

@perivamsi perivamsi removed this from the 0.47.9 milestone Nov 30, 2023
@perivamsi perivamsi removed the backport Automatically create PR on current release branch on merge label Nov 30, 2023
@oleggromov oleggromov force-pushed the bugfix-35503-new branch 2 times, most recently from 997cd59 to 5e49fc2 Compare December 1, 2023 21:08

if (
!_.isEqual(prevProps.parameterValues, this.props.parameterValues) ||
(!prevProps.dashboard && this.props.dashboard)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do initially render Dashboard with dashboard={null}. However, this conditional never works as it's superseded by the first one in this method: prevProps.dashboardId !== this.props.dashboardId.

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 was wrong, so reverting this. Won't be committing after working hours anymore.

if (
!_.isEqual(prevProps.parameterValues, this.props.parameterValues) ||
(!prevProps.dashboard && this.props.dashboard)
!_.isEqual(prevProps.parameters, this.props.parameters)
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 is the actual bug fix.

const canWrite = dashboard?.can_write ?? false;

const dashboardHasCards = dashboard?.dashcards.length > 0 ?? false;
shouldRenderAsNightMode() {
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 have extracted this as a method as it was used in two different methods.

}

renderContent = () => {
const p = this.props;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Everything that's happening here is removing destructured props as they are essentially slag.

const shouldRenderAsNightMode = isNightMode && isFullscreen;

const visibleParameters = getVisibleParameters(parameters);
const p = this.props;
Copy link
Contributor Author

@oleggromov oleggromov Dec 1, 2023

Choose a reason for hiding this comment

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

Same here: instead of wasting lines on avoiding writing this.props, I am putting it into a one-char variable (which is still ugly) that's almost invisible to the eye and removes this unnecessary cruft.


const TEST_CARD = createMockCard();

const TEST_TABLE = createMockTable();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same cruft as everywhere else. We don't need "constants" when they're not exported or at least used multiple times, and absolutely certainly we don't need them at the top of the file — it's ugly and useless albeit quite common.

}

async function setup({ dashboard }: Options = {}) {
const TEST_COLLECTION = createMockCollection();
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 is where they belong. I don't use this SHOUT_CASE for every constant but here I left it as is.

Copy link
Contributor

Choose a reason for hiding this comment

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

Convert to regular camel case straight away?

@oleggromov oleggromov added the backport Automatically create PR on current release branch on merge label Dec 1, 2023
@oleggromov oleggromov added this to the 0.47.10 milestone Dec 1, 2023
@oleggromov oleggromov changed the title WIP Fix card filter connected to a field not causing an update Fix card filter connected to a field not causing an update Dec 1, 2023
Copy link
Contributor

@ranquild ranquild left a comment

Choose a reason for hiding this comment

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

Good overall. Somewhat inconsistent with other integration tests (naming etc).

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: We usually call it SetupOpts

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: We usually omit the return type in setup function

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: We usually name callbacks as onFetch... and return them as it is

Copy link
Contributor Author

@oleggromov oleggromov Dec 4, 2023

Choose a reason for hiding this comment

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

I am not sure it's correct in this case since these aren't really "event handlers", which on* would suggest, but rather callbacks or action dispatchers or whatever you call them. So I'll leave as is if you don't object. I think it reads well.

}

async function setup({ dashboard }: Options = {}) {
const TEST_COLLECTION = createMockCollection();
Copy link
Contributor

Choose a reason for hiding this comment

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

Convert to regular camel case straight away?

Copy link
Contributor

Choose a reason for hiding this comment

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

We usually use these props in setup function so we don't need to deal with spreading

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's actually a very good catch, thanks!

p.addCardToDashboard({
dashId: p.dashboardId,
cardId: p.addCardOnLoad,
tabId: p.dashboard?.tabs[0]?.id ?? null,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Notice ? after dashboard. This was causing exceptions (and failed e2e tests) when dashboard is null.

@oleggromov oleggromov merged commit 2af32bb into master Dec 5, 2023
@oleggromov oleggromov deleted the bugfix-35503-new branch December 5, 2023 16:27
github-actions bot pushed a commit that referenced this pull request Dec 5, 2023
* Rename DashboardHeaderView to match filename
* Fix non updating cards on filter mapping to a field
* Clean up DashboardApp tests a bit
* Clean up Dashboard.jsx cruft
* Add Dashboard componentDidUpdate "unit tests"
* Simplify setup code as per feedback
* Add test for changing dashboard prop in componentDidMount
* Change constant names
* Fix optional chaining in Dashboard
metabase-bot bot added a commit that referenced this pull request Dec 5, 2023
…36419)

* Rename DashboardHeaderView to match filename
* Fix non updating cards on filter mapping to a field
* Clean up DashboardApp tests a bit
* Clean up Dashboard.jsx cruft
* Add Dashboard componentDidUpdate "unit tests"
* Simplify setup code as per feedback
* Add test for changing dashboard prop in componentDidMount
* Change constant names
* Fix optional chaining in Dashboard

Co-authored-by: Oleg Gromov <mail@oleggromov.com>
kulyk added a commit that referenced this pull request Dec 7, 2023
qnkhuat pushed a commit that referenced this pull request Dec 12, 2023
* Rename DashboardHeaderView to match filename
* Fix non updating cards on filter mapping to a field
* Clean up DashboardApp tests a bit
* Clean up Dashboard.jsx cruft
* Add Dashboard componentDidUpdate "unit tests"
* Simplify setup code as per feedback
* Add test for changing dashboard prop in componentDidMount
* Change constant names
* Fix optional chaining in Dashboard
oleggromov added a commit that referenced this pull request Dec 13, 2023
* Rename DashboardHeaderView to match filename
* Fix non updating cards on filter mapping to a field
* Clean up DashboardApp tests a bit
* Clean up Dashboard.jsx cruft
* Add Dashboard componentDidUpdate "unit tests"
* Simplify setup code as per feedback
* Add test for changing dashboard prop in componentDidMount
* Change constant names
* Fix optional chaining in Dashboard
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport Automatically create PR on current release branch on merge .Team/Querying

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Connect a card to a filter in a dashboard doesn't update data

4 participants