Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/core/reducers/addons.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ export function createInternalAddon(
},
isRestartRequired: false,
isWebExtension: false,
isMozillaSignedExtension: false,
};

if (addon.type === ADDON_TYPE_THEME && apiAddon.theme_data) {
Expand Down Expand Up @@ -264,9 +265,15 @@ export function createInternalAddon(
addon.isRestartRequired = apiAddon.current_version.files.some(
(file) => !!file.is_restart_required
);
// The following checks are a bit fragile since only one file needs
// to contain the flag. However, it is highly unlikely to create an
// add-on with mismatched file flags in the current DevHub.
addon.isWebExtension = apiAddon.current_version.files.some(
(file) => !!file.is_webextension
);
addon.isMozillaSignedExtension = apiAddon.current_version.files.some(
(file) => !!file.is_mozilla_signed_extension
);
}

// Remove undefined properties entirely. This is for some legacy code
Expand Down
2 changes: 2 additions & 0 deletions src/core/types/addons.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type AddonFileType = {|
created: string,
hash: string,
id: number,
is_mozilla_signed_extension: boolean,
is_restart_required: boolean,
is_webextension: boolean,
permissions?: Array<string>,
Expand Down Expand Up @@ -152,6 +153,7 @@ export type AddonType = {
linux: ?string,
windows: ?string,
},
isMozillaSignedExtension: boolean,
isRestartRequired: boolean,
isWebExtension: boolean,
themeData?: ThemeData,
Expand Down
31 changes: 7 additions & 24 deletions src/core/utils/compatibility.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
/* global window */
import { oneLine } from 'common-tags';
import mozCompare from 'mozilla-version-comparator';
import UAParser from 'ua-parser-js';

import {
ADDON_TYPE_EXTENSION,
ADDON_TYPE_OPENSEARCH,
CLIENT_APP_ANDROID,
CLIENT_APP_FIREFOX,
INCOMPATIBLE_FIREFOX_FOR_IOS,
INCOMPATIBLE_NO_OPENSEARCH,
INCOMPATIBLE_NOT_FIREFOX,
Expand Down Expand Up @@ -165,25 +162,11 @@ export function getClientCompatibility({
}

export const isQuantumCompatible = ({ addon }) => {
// HACK: we use a hardcoded User Agent string corresponding to MacOS/Firefox
// 57.0 to determine whether the given `addon` is compatible with Quantum.
// The OS is not important as far as it is not `iOS`.
Copy link
Member

Choose a reason for hiding this comment

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

haha, who wrote this comment? 😓

//
// See: https://github.com/mozilla/addons-frontend/issues/3868.
const userAgentInfo = UAParser(oneLine`Mozilla/5.0 (Macintosh; Intel Mac OS X
10.12; rv:57.0) Gecko/20100101 Firefox/57.0`);

const supportsDesktop57 = getClientCompatibility({
addon,
clientApp: CLIENT_APP_FIREFOX,
userAgentInfo,
}).compatible;

const supportsAndroid57 = getClientCompatibility({
addon,
clientApp: CLIENT_APP_ANDROID,
userAgentInfo,
}).compatible;

return supportsDesktop57 || supportsAndroid57;
// TODO: refactor code that inspects the real compatibility
// object and re-use that logic to accomplish this instead.
// https://github.com/mozilla/addons-frontend/issues/3814

// These checks are fragile because future mozilla-signed extensions
// may not be Quantum compatible.
return addon.isWebExtension || addon.isMozillaSignedExtension;
};
10 changes: 10 additions & 0 deletions tests/unit/amo/components/TestAddonBadges.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ describe(__filename, () => {
describe('Quantum compatible badge', () => {
it('does not display a badge when add-on is compatible with Quantum', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_webextension: true,
}],
compatibility: {
[CLIENT_APP_FIREFOX]: {
max: '*',
Expand All @@ -137,6 +140,10 @@ describe(__filename, () => {

it('displays a badge when the addon is not compatible with Quantum', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_mozilla_signed_extension: false,
is_webextension: false,
}],
compatibility: {
[CLIENT_APP_FIREFOX]: {
max: '56.*',
Expand All @@ -156,6 +163,9 @@ describe(__filename, () => {

it('does not display a badge for add-ons that are not extensions', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_webextension: false,
}],
type: ADDON_TYPE_THEME,
compatibility: {
[CLIENT_APP_FIREFOX]: {
Expand Down
1 change: 1 addition & 0 deletions tests/unit/amo/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const fakeAddon = Object.freeze({
created: '2014-11-22T10:09:01Z',
hash: 'a1b2c3d4',
id: 57721,
is_mozilla_signed_extension: false,
is_restart_required: false,
is_webextension: true,
permissions: ['activeTab', 'webRequest'],
Expand Down
55 changes: 47 additions & 8 deletions tests/unit/core/reducers/test_addons.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ describe(__filename, () => {
},
isRestartRequired: false,
isWebExtension: true,
isMozillaSignedExtension: false,
});
});

Expand Down Expand Up @@ -109,6 +110,7 @@ describe(__filename, () => {
},
isRestartRequired: false,
isWebExtension: true,
isMozillaSignedExtension: false,
};
delete expectedTheme.theme_data;

Expand Down Expand Up @@ -278,9 +280,7 @@ describe(__filename, () => {

it('exposes `isWebExtension` attribute from current version files', () => {
const addon = createFakeAddon({
files: [
{ ...fakeAddon.current_version.files[0], is_webextension: true },
],
files: [{ is_webextension: true }],
});

const state = addons(undefined,
Expand All @@ -290,9 +290,7 @@ describe(__filename, () => {

it('sets `isWebExtension` to `false` when add-on is not a web extension', () => {
const addon = createFakeAddon({
files: [
{ ...fakeAddon.current_version.files[0], is_webextension: false },
],
files: [{ is_webextension: false }],
});

const state = addons(undefined,
Expand All @@ -311,8 +309,8 @@ describe(__filename, () => {
it('sets `isWebExtension` to `true` when any file declares it', () => {
const addon = createFakeAddon({
files: [
{ ...fakeAddon.current_version.files[0], is_webextension: false },
{ ...fakeAddon.current_version.files[0], is_webextension: true },
{ is_webextension: false },
{ is_webextension: true },
],
});

Expand All @@ -321,6 +319,47 @@ describe(__filename, () => {
expect(state[addon.slug].isWebExtension).toBe(true);
});

it('exposes `isMozillaSignedExtension` from current version files', () => {
const addon = createFakeAddon({
files: [{ is_mozilla_signed_extension: true }],
});

const state = addons(undefined,
loadAddons(createFetchAddonResult(addon).entities));
expect(state[addon.slug].isMozillaSignedExtension).toBe(true);
});

it('sets `isMozillaSignedExtension` to `false` when not declared', () => {
const addon = createFakeAddon({
files: [{ is_mozilla_signed_extension: false }],
});

const state = addons(undefined,
loadAddons(createFetchAddonResult(addon).entities));
expect(state[addon.slug].isMozillaSignedExtension).toBe(false);
});

it('sets `isMozillaSignedExtension` to `false` without files', () => {
const addon = createFakeAddon({ files: [] });

const state = addons(undefined,
loadAddons(createFetchAddonResult(addon).entities));
expect(state[addon.slug].isMozillaSignedExtension).toBe(false);
});

it('sets `isMozillaSignedExtension` to `true` when any file declares it', () => {
const addon = createFakeAddon({
files: [
{ is_mozilla_signed_extension: false },
{ is_mozilla_signed_extension: true },
],
});

const state = addons(undefined,
loadAddons(createFetchAddonResult(addon).entities));
expect(state[addon.slug].isMozillaSignedExtension).toBe(true);
});

describe('fetchAddon', () => {
const defaultParams = Object.freeze({
slug: 'addon-slug',
Expand Down
92 changes: 89 additions & 3 deletions tests/unit/core/utils/test_compatibility.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import {
INCOMPATIBLE_OVER_MAX_VERSION,
INCOMPATIBLE_UNDER_MIN_VERSION,
INCOMPATIBLE_UNSUPPORTED_PLATFORM,
OS_ALL,
OS_ANDROID,
OS_LINUX,
OS_MAC,
OS_WINDOWS,
} from 'core/constants';
import { createInternalAddon } from 'core/reducers/addons';
import {
Expand Down Expand Up @@ -616,8 +620,33 @@ describe(__filename, () => {
});

describe('isQuantumCompatible', () => {
it('returns `true` when add-on is compatible', () => {
it('returns `true` when webextension is compatible', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_mozilla_signed_extension: false,
is_webextension: true,
platform: OS_ALL,
}],
name: 'Some Quantum WebExtension',
compatibility: {
[CLIENT_APP_FIREFOX]: {
max: '*',
min: '53.0',
},
},
is_strict_compatibility_enabled: false,
}));

expect(isQuantumCompatible({ addon })).toEqual(true);
});

it('returns `true` when mozilla extension is compatible', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_mozilla_signed_extension: true,
is_webextension: false,
platform: OS_ALL,
}],
name: 'Firefox Multi-Account Containers',
compatibility: {
[CLIENT_APP_FIREFOX]: {
Expand All @@ -631,8 +660,53 @@ describe(__filename, () => {
expect(isQuantumCompatible({ addon })).toEqual(true);
});

it('returns `false` when add-on is not compatible', () => {
it('returns `true` for windows-only mozilla extensions', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_mozilla_signed_extension: true,
is_webextension: false,
platform: OS_WINDOWS,
}],
name: 'Windows only mozilla extension',
compatibility: {
[CLIENT_APP_FIREFOX]: {
max: '*',
min: '53.0',
},
},
is_strict_compatibility_enabled: false,
}));

expect(isQuantumCompatible({ addon })).toEqual(true);
});

it('returns `true` for linux-only mozilla extensions', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_mozilla_signed_extension: true,
is_webextension: false,
platform: OS_LINUX,
}],
name: 'Linux only mozilla extension',
compatibility: {
[CLIENT_APP_FIREFOX]: {
max: '*',
min: '53.0',
},
},
is_strict_compatibility_enabled: false,
}));

expect(isQuantumCompatible({ addon })).toEqual(true);
});

it('returns `false` when non-webextesion is not compatible', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_mozilla_signed_extension: false,
is_webextension: false,
platform: OS_ALL,
}],
name: 'Firebug',
compatibility: {
[CLIENT_APP_FIREFOX]: {
Expand All @@ -646,8 +720,20 @@ describe(__filename, () => {
expect(isQuantumCompatible({ addon })).toEqual(false);
});

it('returns `true` when add-on is compatible with one of the platforms', () => {
it('returns `false` for add-ons without a current version', () => {
const addon = createInternalAddon(createFakeAddon({
current_version: null,
}));

expect(isQuantumCompatible({ addon })).toEqual(false);
});

it('returns `true` when Android webextension is compatible', () => {
const addon = createInternalAddon(createFakeAddon({
files: [{
is_webextension: true,
platform: OS_ANDROID,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I added this, the old code was failing because of the desktop UA string. Oops.

Copy link
Member

Choose a reason for hiding this comment

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

😞

}],
compatibility: {
// This platform is not compatible...
[CLIENT_APP_FIREFOX]: {
Expand Down
1 change: 1 addition & 0 deletions tests/unit/disco/containers/TestDiscoPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ describe(__filename, () => {
mac: undefined,
windows: undefined,
},
isMozillaSignedExtension: false,
isRestartRequired: false,
isWebExtension: true,
}]);
Expand Down