diff --git a/src/amo/actions/reviews.js b/src/amo/actions/reviews.js index 8164c5da5f7..4f9414f10bf 100644 --- a/src/amo/actions/reviews.js +++ b/src/amo/actions/reviews.js @@ -86,6 +86,7 @@ export function createInternalReview( reviewAddon: { iconUrl: review.addon.icon_url, id: review.addon.id, + // $FlowIgnore: the add-on's name cannot be falsey. name: selectLocalizedContent(review.addon.name, lang), slug: review.addon.slug, }, diff --git a/src/amo/components/HomepageShelves/index.js b/src/amo/components/HomepageShelves/index.js index c5b4f0d1602..d77861e7f67 100644 --- a/src/amo/components/HomepageShelves/index.js +++ b/src/amo/components/HomepageShelves/index.js @@ -2,6 +2,7 @@ import url from 'url'; import * as React from 'react'; +import invariant from 'invariant'; import LandingAddonsCard from 'amo/components/LandingAddonsCard'; import LoadingText from 'amo/components/LoadingText'; @@ -68,6 +69,9 @@ export const HomepageShelvesBase = (props: InternalProps): React.Node => { } else { shelvesContent = shelves.map((shelf) => { const { addons, addonType, endpoint, footer, title, url: apiUrl } = shelf; + + invariant(title, 'title is required'); + const shelfKey = title.replace(/\s/g, '-'); const footerText = footer.text diff --git a/src/amo/pages/AddonInfo/index.js b/src/amo/pages/AddonInfo/index.js index a563d734b9c..15bdc7545e0 100644 --- a/src/amo/pages/AddonInfo/index.js +++ b/src/amo/pages/AddonInfo/index.js @@ -118,7 +118,7 @@ export class AddonInfoBase extends React.Component { const needsLicenceText = addonVersion && addonVersion.license && - addonVersion.license.text === undefined; + addonVersion.license.text === null; if ( addon && addon.currentVersionId && diff --git a/src/amo/reducers/addons.js b/src/amo/reducers/addons.js index 89b93ae078a..9bb36d5a248 100644 --- a/src/amo/reducers/addons.js +++ b/src/amo/reducers/addons.js @@ -195,7 +195,9 @@ export const selectLocalizedUrlWithOutgoing = ( ): UrlWithOutgoing | null => { if (url && url.url && url.outgoing) { return { + // $FlowIgnore: this can't be `null` because we check before. url: selectLocalizedContent(url.url, lang), + // $FlowIgnore: this can't be `null` because we check before. outgoing: selectLocalizedContent(url.outgoing, lang), }; } @@ -234,6 +236,7 @@ export function createInternalAddon( last_updated: apiAddon.last_updated, latest_unlisted_version: apiAddon.latest_unlisted_version, locale_disambiguation: apiAddon.locale_disambiguation, + // $FlowIgnore: the add-on's name cannot be falsey. name: selectLocalizedContent(apiAddon.name, lang), previews: apiAddon.previews ? createInternalPreviews(apiAddon.previews, lang) diff --git a/src/amo/reducers/autocomplete.js b/src/amo/reducers/autocomplete.js index b119ec2dd02..689b7668808 100644 --- a/src/amo/reducers/autocomplete.js +++ b/src/amo/reducers/autocomplete.js @@ -29,7 +29,7 @@ export type ExternalSuggestion = {| export type SuggestionType = {| addonId: number, iconUrl: string, - name: string, + name: string | null, promoted: Array, type: string, url: string, diff --git a/src/amo/reducers/blocks.js b/src/amo/reducers/blocks.js index 8c393790f80..57478c64183 100644 --- a/src/amo/reducers/blocks.js +++ b/src/amo/reducers/blocks.js @@ -24,7 +24,7 @@ export type ExternalBlockType = {| export type BlockType = {| ...ExternalBlockType, - name: string, + name: string | null, |}; export type BlocksState = {| diff --git a/src/amo/reducers/home.js b/src/amo/reducers/home.js index 3c76104f167..cfb19e5c409 100644 --- a/src/amo/reducers/home.js +++ b/src/amo/reducers/home.js @@ -39,7 +39,7 @@ export type InternalPrimaryHeroShelfExternalAddonType = {| id: string, guid: string, homepage: UrlWithOutgoing | null, - name: string, + name: string | null, type: string, |}; @@ -116,18 +116,18 @@ export type ExternalSecondaryHeroShelfType = {| export type LinkWithTextType = {| url: string, outgoing: string, - text: string, + text: string | null, |}; export type SecondaryHeroModuleType = {| icon: string, - description: string, + description: string | null, cta: LinkWithTextType | null, |}; export type SecondaryHeroShelfType = {| - headline: string, - description: string, + headline: string | null, + description: string | null, cta: LinkWithTextType | null, modules: Array, |} | null; @@ -152,7 +152,7 @@ export type ExternalResultShelfType = {| |}; export type ResultShelfType = {| - title: string, + title: string | null, url: string, endpoint: string, addonType: AddonTypeType, diff --git a/src/amo/reducers/utils.js b/src/amo/reducers/utils.js index ed2c93537d5..f9cf4f2ebbd 100644 --- a/src/amo/reducers/utils.js +++ b/src/amo/reducers/utils.js @@ -1,14 +1,18 @@ +/* @flow */ import invariant from 'invariant'; import type { LocalizedString } from 'amo/types/api'; -import type { CategoryEntry } from './categories'; -import type { ExternalAddonType, PromotedType } from '../types/addons'; +import type { + ExternalAddonType, + PartialExternalAddonType, + PromotedType, +} from '../types/addons'; export const selectLocalizedContent = ( - field: LocalizedString, + field: ?LocalizedString, lang: string, -) => { +): string | null => { invariant(lang, 'lang must not be empty'); if (!field) { return null; @@ -22,9 +26,9 @@ export const selectLocalizedContent = ( }; export const selectCategoryObject = ( - apiAddon: ExternalAddonType, -): CategoryEntry => { - return apiAddon.categories; + apiAddon: ExternalAddonType | PartialExternalAddonType, +): Array => { + return apiAddon.categories || []; }; export const makeInternalPromoted = ( diff --git a/src/amo/reducers/versions.js b/src/amo/reducers/versions.js index c6aca46308c..0e954dd023d 100644 --- a/src/amo/reducers/versions.js +++ b/src/amo/reducers/versions.js @@ -77,7 +77,7 @@ export type ExternalVersionLicenseType = {| type PartialVersionLicenseType = {| name: string | null, - text?: string, + text: string | null, url: string, |}; @@ -98,7 +98,7 @@ export type AddonVersionType = { isStrictCompatibilityEnabled: boolean, license: VersionLicenseType | null, file: AddonFileType | null, - releaseNotes?: string, + releaseNotes: string | null, version: string, }; @@ -146,7 +146,7 @@ export const createInternalVersion = ( name: selectLocalizedContent(version.license.name, lang), text: version.license.text === undefined - ? undefined + ? null : selectLocalizedContent(version.license.text, lang), url: version.license.url, } diff --git a/src/amo/types/addons.js b/src/amo/types/addons.js index 36295027035..d9c2821deab 100644 --- a/src/amo/types/addons.js +++ b/src/amo/types/addons.js @@ -59,7 +59,7 @@ export type ExternalLanguageToolType = {| export type LanguageToolType = {| ...ExternalLanguageToolType, - name: string, + name: string | null, |}; export type PromotedType = {| @@ -83,7 +83,7 @@ export type PreviewType = {| thumbnail_h: number, thumbnail_src: string, thumbnail_w: number, - title: string, + title: string | null, w: number, |}; diff --git a/tests/unit/amo/reducers/test_versions.js b/tests/unit/amo/reducers/test_versions.js index a4d9a606c8a..9d6201c4a0e 100644 --- a/tests/unit/amo/reducers/test_versions.js +++ b/tests/unit/amo/reducers/test_versions.js @@ -175,10 +175,10 @@ describe(__filename, () => { }); }); - it('returns undefined for license.text if it is missing from the response', () => { + it('returns null for license.text if it is missing from the response', () => { // fakeVersion does not include license.text. const version = createInternalVersion(fakeVersion, lang); - expect(version.license.text).toEqual(undefined); + expect(version.license.text).toEqual(null); }); // See https://github.com/mozilla/addons-frontend/issues/11337