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

Implement API, saga and reducer code to interact with TAAR Lite service via addons-server #4904

Merged

Conversation

bobsilverberg
Copy link
Contributor

@codecov-io
Copy link

codecov-io commented May 1, 2018

Codecov Report

Merging #4904 into master will increase coverage by 0.03%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    mozilla/addons-frontend#4904      +/-   ##
==========================================
+ Coverage   96.49%   96.52%   +0.03%     
==========================================
  Files         208      211       +3     
  Lines        4823     4869      +46     
  Branches      959      962       +3     
==========================================
+ Hits         4654     4700      +46     
  Misses        151      151              
  Partials       18       18
Impacted Files Coverage Δ
src/amo/sagas/index.js 100% <ø> (ø) ⬆️
src/amo/store.js 100% <ø> (ø) ⬆️
src/amo/sagas/recommendations.js 100% <100%> (ø)
src/amo/reducers/recommendations.js 100% <100%> (ø)
src/amo/api/recommendations.js 100% <100%> (ø)
src/amo/utils.js 100% <0%> (ø) ⬆️
src/amo/components/Addon/index.js 100% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2267785...f41d02c. Read the comment docs.

@bobsilverberg bobsilverberg requested a review from willdurand May 1, 2018 14:27
Copy link
Member

@willdurand willdurand left a comment

Choose a reason for hiding this comment

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

Good job, I am blocking this PR because I would like your input on the recommandations state shape. I think we should not have undefined properties and always have the same shape (the Flow type for RecommendationsState looks perfect to me).

| AbortFetchRecommendationsAction
| FetchRecommendationsAction
| LoadRecommendationsAction
;
Copy link
Member

Choose a reason for hiding this comment

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

I think we put semi-colons on the last line, never alone.

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 think I got that from https://github.com/mozilla/addons-frontend/blob/master/src/amo/reducers/collections.js#L724, but you're right, pretty much everywhere else we put it on the end of the lint.

Copy link
Member

Choose a reason for hiding this comment

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

ah yes, consistency is not our best strength 😅

byGuid: {
...state.byGuid,
[action.payload.guid]: {
loading: false,
Copy link
Member

Choose a reason for hiding this comment

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

According to the Flow def, we should have more properties here no?

byGuid: {
...state.byGuid,
[action.payload.guid]: {
loading: true,
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

api: state.api, guid, recommended,
};
const recommendations = yield call(api.getRecommendations, params);
const { outcome } = recommendations;
Copy link
Member

Choose a reason for hiding this comment

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

if you want to destructure an object and have different variable names, you can do:

const { results: addons, fallback_reason: fallbackReason, outcome } = recommendations;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, thanks!

export const abortFetchRecommendations = ({
guid,
}: AbortFetchRecommendationsParams = {}): AbortFetchRecommendationsAction => {
return {
Copy link
Member

Choose a reason for hiding this comment

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

no invariant here?

import { createApiResponse } from 'tests/unit/helpers';
import {
dispatchClientMetadata,
} from 'tests/unit/amo/helpers';
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: this could be one a single line.

}));

expect(state.byGuid[guid].loading).toEqual(true);
expect(state.byGuid[guid].addons).toEqual(undefined);
Copy link
Member

Choose a reason for hiding this comment

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

According to the flow def, there is always an addon array that can be empty.

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 updated that so it can be null, and updated this test.

expect(state.byGuid[guid].addons).toEqual(undefined);
});


Copy link
Member

Choose a reason for hiding this comment

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

Extra blank line


const loadedRecommendations = getRecommendationsByGuid({ guid, state });

expect(loadedRecommendations).not.toEqual(null);
Copy link
Member

Choose a reason for hiding this comment

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

I understand this line but it is (implicitly) covered by the line below no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. I'll remove it.



describe(__filename, () => {
let clientData;
Copy link
Member

Choose a reason for hiding this comment

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

Is this really necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope. :)

@bobsilverberg
Copy link
Contributor Author

Thanks for the review @willdurand. I'm submitting my changes for you to have another look. This is currently failing the Flow check as it will need Flow 0.71, so ignore the CI failures for now. I won't land it until those are fixed.

@bobsilverberg bobsilverberg requested a review from willdurand May 3, 2018 13:52
@willdurand
Copy link
Member

@bobsilverberg thanks, you can rebase now if you want.

@bobsilverberg bobsilverberg force-pushed the recommendations-api-4867 branch from 4a1bdcc to 8b0d81c Compare May 3, 2018 16:22
@bobsilverberg
Copy link
Contributor Author

This is ready for another review, thanks @willdurand.

Copy link
Member

@willdurand willdurand left a comment

Choose a reason for hiding this comment

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

r+wc

👍


export const abortFetchRecommendations = ({
guid,
}: AbortFetchRecommendationsParams = {}): AbortFetchRecommendationsAction => {
Copy link
Member

Choose a reason for hiding this comment

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

I would not specify a default empty object here because guid is mandatory.

errorHandlerId,
guid,
recommended,
}: FetchRecommendationsParams = {}): FetchRecommendationsAction => {
Copy link
Member

Choose a reason for hiding this comment

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

Here too, I would not add the default empty object. It's not really clear to me why we have some actions with default empty objects and others without... I would be in favor of not doing this because it would raise a warning/error in development.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. That was code borrowed from another reducer and modified, but with required arguments there's no reason to default to {}.

src/amo/store.js Outdated
@@ -51,6 +52,7 @@ export default function createStore({
landing,
languageTools,
redirectTo,
recommendations,
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be before redirectTo?

= 'LOAD_RECOMMENDATIONS';

export type Recommendations = {|
addons: Array<ExternalAddonType> | null,
Copy link
Member

Choose a reason for hiding this comment

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

Because you use createInternalAddon() in the reducer, I suppose the type should be AddonType.

outcome,
}: LoadRecommendationsParams = {}): LoadRecommendationsAction => {
invariant(addons, 'addons is required');
invariant(fallbackReason, 'fallbackReason is required');
Copy link
Member

Choose a reason for hiding this comment

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

The API documentation says the fallback_reason is "nullable": http://addons-server.readthedocs.io/en/latest/topics/api/addons.html#recommendations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, correct, good call!

addons: Array<ExternalAddonType> | null,
fallbackReason: string | null,
loading: boolean,
outcome: string | null,
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to specify the allowed values? The API documentation describes the following possible values:

outcome (string) – Outcome of the response returned. Will be either: recommended - responses from recommendation service; recommended_fallback - service timed out or returned empty results so we returned fallback; curated - recommended=False was requested so fallback returned.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the app doesn't care what the value is (i.e., all it does is record the value, but it never makes any decisions based on the value), I thought it might make sense to leave this open. Theoretically the API could change the strings, or add a string, and it shouldn't break anything.

However this does seem to go against our use of Flow, so I will update this to a type which allows specific strings, and I'll do the same for fallbackReason.

Copy link
Member

Choose a reason for hiding this comment

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

If you spend more than 5-10min trying to convince Flow, a string type will be fine :)

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 didn't have to spend any time trying to convince Flow, so it's now a specific type. :-)

outcome,
}));
} catch (error) {
log.warn(`Failed to fetch user collections: ${error}`);
Copy link
Member

Choose a reason for hiding this comment

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

s/user collections/recommendations

src/amo/store.js Outdated
@@ -51,6 +52,7 @@ export default function createStore({
landing,
languageTools,
redirectTo,
recommendations,
Copy link
Member

Choose a reason for hiding this comment

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

In addition, I noticed you have added the reducer here. Do you want to also add the saga in the rootSaga?

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, I missed that, and added it in #4942, but it makes sense to add it in this patch. Thanks. 👍

@bobsilverberg bobsilverberg merged commit 1d66889 into mozilla:master May 7, 2018
@bobsilverberg
Copy link
Contributor Author

Oops, I notice that I didn't use the new types for fallbackReason and outcome in LoadRecommendationsParams. I'll address that in PR #4942.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement API, saga and reducer code to interact with TAAR Lite service via addons-server
3 participants