-
Notifications
You must be signed in to change notification settings - Fork 400
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
Implement API, saga and reducer code to interact with TAAR Lite service via addons-server #4904
Conversation
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
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.
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).
src/amo/reducers/recommendations.js
Outdated
| AbortFetchRecommendationsAction | ||
| FetchRecommendationsAction | ||
| LoadRecommendationsAction | ||
; |
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 we put semi-colons on the last line, never alone.
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 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.
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.
ah yes, consistency is not our best strength 😅
src/amo/reducers/recommendations.js
Outdated
byGuid: { | ||
...state.byGuid, | ||
[action.payload.guid]: { | ||
loading: false, |
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.
According to the Flow def, we should have more properties here no?
src/amo/reducers/recommendations.js
Outdated
byGuid: { | ||
...state.byGuid, | ||
[action.payload.guid]: { | ||
loading: true, |
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.
Same here.
src/amo/sagas/recommendations.js
Outdated
api: state.api, guid, recommended, | ||
}; | ||
const recommendations = yield call(api.getRecommendations, params); | ||
const { outcome } = recommendations; |
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.
if you want to destructure an object and have different variable names, you can do:
const { results: addons, fallback_reason: fallbackReason, outcome } = recommendations;
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.
Nice, thanks!
src/amo/reducers/recommendations.js
Outdated
export const abortFetchRecommendations = ({ | ||
guid, | ||
}: AbortFetchRecommendationsParams = {}): AbortFetchRecommendationsAction => { | ||
return { |
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.
no invariant
here?
import { createApiResponse } from 'tests/unit/helpers'; | ||
import { | ||
dispatchClientMetadata, | ||
} from 'tests/unit/amo/helpers'; |
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.
nitpick: this could be one a single line.
})); | ||
|
||
expect(state.byGuid[guid].loading).toEqual(true); | ||
expect(state.byGuid[guid].addons).toEqual(undefined); |
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.
According to the flow def, there is always an addon
array that can be empty.
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 updated that so it can be null, and updated this test.
expect(state.byGuid[guid].addons).toEqual(undefined); | ||
}); | ||
|
||
|
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.
Extra blank line
|
||
const loadedRecommendations = getRecommendationsByGuid({ guid, state }); | ||
|
||
expect(loadedRecommendations).not.toEqual(null); |
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 understand this line but it is (implicitly) covered by the line below no?
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.
True. I'll remove it.
|
||
|
||
describe(__filename, () => { | ||
let clientData; |
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.
Is this really necessary?
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.
Nope. :)
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 thanks, you can rebase now if you want. |
4a1bdcc
to
8b0d81c
Compare
This is ready for another review, thanks @willdurand. |
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.
r+wc
👍
src/amo/reducers/recommendations.js
Outdated
|
||
export const abortFetchRecommendations = ({ | ||
guid, | ||
}: AbortFetchRecommendationsParams = {}): AbortFetchRecommendationsAction => { |
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 would not specify a default empty object here because guid
is mandatory.
src/amo/reducers/recommendations.js
Outdated
errorHandlerId, | ||
guid, | ||
recommended, | ||
}: FetchRecommendationsParams = {}): FetchRecommendationsAction => { |
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.
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.
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.
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, |
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.
Shouldn't this be before redirectTo
?
src/amo/reducers/recommendations.js
Outdated
= 'LOAD_RECOMMENDATIONS'; | ||
|
||
export type Recommendations = {| | ||
addons: Array<ExternalAddonType> | null, |
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.
Because you use createInternalAddon()
in the reducer, I suppose the type should be AddonType
.
src/amo/reducers/recommendations.js
Outdated
outcome, | ||
}: LoadRecommendationsParams = {}): LoadRecommendationsAction => { | ||
invariant(addons, 'addons is required'); | ||
invariant(fallbackReason, 'fallbackReason is required'); |
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.
The API documentation says the fallback_reason
is "nullable": http://addons-server.readthedocs.io/en/latest/topics/api/addons.html#recommendations
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.
Ah, correct, good call!
src/amo/reducers/recommendations.js
Outdated
addons: Array<ExternalAddonType> | null, | ||
fallbackReason: string | null, | ||
loading: boolean, | ||
outcome: string | null, |
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.
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.
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.
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
.
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.
If you spend more than 5-10min trying to convince Flow, a string
type will be fine :)
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 didn't have to spend any time trying to convince Flow, so it's now a specific type. :-)
src/amo/sagas/recommendations.js
Outdated
outcome, | ||
})); | ||
} catch (error) { | ||
log.warn(`Failed to fetch user collections: ${error}`); |
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.
s/user collections/recommendations
src/amo/store.js
Outdated
@@ -51,6 +52,7 @@ export default function createStore({ | |||
landing, | |||
languageTools, | |||
redirectTo, | |||
recommendations, |
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.
In addition, I noticed you have added the reducer here. Do you want to also add the saga in the rootSaga
?
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.
Yeah, I missed that, and added it in #4942, but it makes sense to add it in this patch. Thanks. 👍
Oops, I notice that I didn't use the new types for |
Fixes mozilla/addons#11690