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

[No QA] Add Pusher Automated Tests #1153

Merged
merged 31 commits into from
Jan 18, 2021
Merged

[No QA] Add Pusher Automated Tests #1153

merged 31 commits into from
Jan 18, 2021

Conversation

marcaaron
Copy link
Contributor

Details

Second attempt to make Pusher tests. Closed the first PR here #771

Fixed Issues

Fixes https://github.com/Expensify/Expensify/issues/145497

Tests

Automated

Tested On

Screenshots

@marcaaron marcaaron self-assigned this Jan 1, 2021
@github-actions
Copy link
Contributor

github-actions bot commented Jan 1, 2021

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@marcaaron marcaaron marked this pull request as ready for review January 1, 2021 18:50
@marcaaron marcaaron requested a review from a team as a code owner January 1, 2021 18:50
@botify botify requested review from nickmurray47 and removed request for a team January 1, 2021 18:50
@marcaaron marcaaron requested review from a team and removed request for nickmurray47 January 1, 2021 18:50
@botify botify requested review from nickmurray47 and removed request for a team January 1, 2021 18:50
@marcaaron marcaaron removed the request for review from nickmurray47 January 1, 2021 18:50
AndrewGable
AndrewGable previously approved these changes Jan 11, 2021
Copy link
Contributor

@AndrewGable AndrewGable left a comment

Choose a reason for hiding this comment

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

Looking a whole lot better! Adding @tgolen for review since he had comments on the last PR.

Copy link
Contributor

@tgolen tgolen left a comment

Choose a reason for hiding this comment

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

This looks like a good use for the tests, but I'm concerned that it's only testing half the flow. What about including more of the flow such as, using Report.addAction(), testing that an optimistic action is created in Onyx, then the pusher event happens, and verify that the optimistic action was replaced by the real action?

This comment is more of a NAB, but I also really like when tests conform to the format:

// Given <initial_condition>
...  code that sets initial condition
// When <something_happens>
... code that does something
// Then <expectation>
... code that performs the assertion

I know we use this pattern a lot in Chronos and I think it's really great because it provides lots of context for someone else that has to come in to maintain the test and understand the "why" behind everything that was done. Since we only have a few tests written so far, I think it would be a good time to adopt that same format, but if you are not sold on it, I can pull it out into a separate discussion.

Comment on lines 49 to 50
Onyx.set(ONYXKEYS.SESSION, {accountID: 1, email: 'test@test.com'});
return waitForPromisesToResolve()
Copy link
Contributor

Choose a reason for hiding this comment

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

I still haven't quite gotten the hang of these, so forgive me if this isn't how it's meant to be done... is the test that has been written any different than doing this?

return Onyx.set(ONYXKEYS.SESSION, {accountID: 1, email: 'test@test.com'})

My thinking is just that it's odd to see waitForPromisesToResolve() being used when the promise returned from Onyx.set() should resolve and work as well (and it's more obvious what is happening because the test uses the same promise chain).

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 makes sense! And I wouldn't mind updating it, but want to walk you through my thought process here to see if you have similar thoughts...

We could wait for Onyx.set() instead of doing waitForPromisesToResolve(), but I was thinking that for consistency we might want to default to waitForPromisesToResolve(). Even though unnecessary it might make it easier to understand how these tests are structured and deal with async code that doesn't necessarily have an "await-able" promise. Maybe this practice actually makes it harder to tell that's what waitForPromisesToResolve() is for?

Another thought I keep having is that if "everything async returned a Promise" (or even just the async "actions") then the test code might be more straight-forward and it would be more obvious to tell what exactly we are waiting for.

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'll change this for now since I think I did have it this way at one point.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, you brought up some really good points. What I'd like to avoid is creating a situation where people get too promise-happy and just return promises from everything. That essentially promotes a ton of promise chains, and that was what plagued the application from an early age. I had to do a lot of work to remove all those promise chains and I'd hate to go back down that path. So, now that I think about it, I think your original solution here is actually superior.

tests/actions/ReportTest.js Show resolved Hide resolved

// Once this happens we should see the comment get processed by the callback and added to the
// storage so we must wait for promises to resolve again and then verify the data is in Onyx.
return waitForPromisesToResolve();
Copy link
Contributor

Choose a reason for hiding this comment

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

I can see how maybe this is necessary to prevent any race conditions with the local data stored in reportActions not being up-to-date with Onyx yet.

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 right. The callback should happen in realtime and then we set the data async via Onyx.

tests/actions/ReportTest.js Outdated Show resolved Hide resolved
@marcaaron marcaaron changed the title [No QA] Add Pusher Automated Tests [HOLD][No QA] Add Pusher Automated Tests Jan 12, 2021
@marcaaron
Copy link
Contributor Author

Alright, so I started to write a much better test for Report.addAction(), but it was so much better than it ended up revealing a bug in react-native-onyx. Fixed the bug over there and also cleaned up the main tests in that repo.

https://github.com/Expensify/react-native-onyx/pull/36/files

I know we use this pattern a lot in Chronos and I think it's really great because it provides lots of context for someone else that has to come in to maintain the test and understand the "why" behind everything that was done

Yeah that does sound pretty organized. I'll check out the Chronos tests and investigate.


// When using the Pusher mock the act of calling Pusher.isSubscribed will create a
// channel already in a subscribed state. These methods are normally used to prevent
// duplicated subscriptions, but we don't need them for this test.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// duplicated subscriptions, but we don't need them for this test.
// duplicated subscriptions, but we don't need them for this test so forcing them to return false will make the testing less complex.

This adds a little more clarity.

},
}))
.then(() => {
// This is a fire and forget response, but one it completes we should be able to verify that we
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// This is a fire and forget response, but one it completes we should be able to verify that we
// This is a fire and forget response, but once it completes we should be able to verify that we

expect(resultAction).toEqual(REPORT_ACTION);
})
.then(() => {
// Now that we are subscribed we need to simulate a reportComment action Pusher event.
Copy link
Contributor

Choose a reason for hiding this comment

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

// Now that we are subscribed

Subscribed to what? Is this referring to the original Pusher subscription or to Onyx? This reads a little weird because I would expect the thing before this to be code that does subscribing, but the thing before this is adding the report action.

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 can make this more explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It probably made more sense before when the thing immediately before this was subscribeToReportComments()

reportAction: REPORT_ACTION,
});

// Once this happens we should see the comment get processed by the callback and added to the
Copy link
Contributor

Choose a reason for hiding this comment

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

// Once this happens

"this" could be referring to a number of things, so be more explicit

Copy link
Contributor

Choose a reason for hiding this comment

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

the callback

This is also ambiguous. Is it the pusher callback, the onyx callback, or a different callback entirely?

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 can make this more explicit.


// Verify that our action is no longer in the loading state
REPORT_ACTION.loading = false;
expect(resultAction).toEqual(REPORT_ACTION);
Copy link
Contributor

Choose a reason for hiding this comment

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

Using a different assertion might make it a little more clear what's being tested and prevents the need to modify the contents of REPORT_ACTION (which is not quite intuitive as to why it's necessary to modify REPORT_ACTION).

Suggestion:

expect(resultAction.loading).toEqual(false);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is much better

})
.then(() => {
const resultAction = reportActions[ACTION_ID];
expect(resultAction).toEqual(REPORT_ACTION);
Copy link
Contributor

Choose a reason for hiding this comment

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

Adding this assertion will help identify that yes, this is definitely an optimistic comment, and not the final result.

expect(resultAction.loading).toEqual(true);

This, of course, is already implied in the current assertion, but it's an extra mental jump that has to be made which isn't totally obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep that makes sense to me. I think it'll be a more interesting test when the clientID stuff comes along. But this is mostly what we are looking for now and proves that the action was handled from the Pusher payload.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this will look cool once the clientID stuff happens, and it will be a perfect use for these tests!

tgolen
tgolen previously approved these changes Jan 12, 2021
Copy link
Contributor

@tgolen tgolen left a comment

Choose a reason for hiding this comment

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

Looks great, thanks for those improvements!

@marcaaron marcaaron changed the title [HOLD][No QA] Add Pusher Automated Tests [No QA] Add Pusher Automated Tests Jan 13, 2021
@marcaaron
Copy link
Contributor Author

Taking this one off hold .

@marcaaron
Copy link
Contributor Author

Also added a README over here if y'all are interested

#1236

AndrewGable
AndrewGable previously approved these changes Jan 14, 2021
Copy link
Contributor

@AndrewGable AndrewGable left a comment

Choose a reason for hiding this comment

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

Great improvement 👍

@AndrewGable AndrewGable merged commit d1cff08 into master Jan 18, 2021
@AndrewGable AndrewGable deleted the marcaaron-pusher-tests branch January 18, 2021 19:32
@github-actions github-actions bot locked and limited conversation to collaborators Jan 18, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants