From 8f2ec8be567d58d65f8e1f652dd3dbc5f0213cc3 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Tue, 28 Nov 2023 01:37:38 +0000 Subject: [PATCH] Bug 1863400 - Part 7: Move about:welcome Karma unit tests to browser/components/aboutwelcome folder. r=pdahiya Depends on D193121 Differential Revision: https://phabricator.services.mozilla.com/D193122 --- .../actors/AboutWelcomeParent.sys.mjs | 3 +- .../content-src/components/HelpText.jsx | 2 +- .../aboutwelcome/karma.mc.config.js | 243 ++++++ .../modules}/AWScreenUtils.jsm | 1 + .../modules/AboutWelcomeDefaults.jsm | 3 +- browser/components/aboutwelcome/package.json | 19 + ...er_aboutwelcome_multistage_addonspicker.js | 2 +- ...boutwelcome_multistage_languageSwitcher.js | 2 +- .../browser_aboutwelcome_multistage_mr.js | 2 +- .../tests/unit}/AWScreenUtils.test.jsx | 6 +- .../tests/unit}/CTAParagraph.test.jsx | 2 +- .../tests/unit}/HelpText.test.jsx | 4 +- .../tests/unit}/HeroImage.test.jsx | 2 +- .../tests/unit}/LinkParagraph.test.jsx | 2 +- .../tests/unit/MRColorways.test.jsx | 328 ++++++++ .../tests/unit}/MSLocalized.test.jsx | 2 +- .../tests/unit}/MobileDownloads.test.jsx | 4 +- .../tests/unit}/MultiSelect.test.jsx | 2 +- .../tests/unit}/MultiStageAWProton.test.jsx | 6 +- .../unit}/MultiStageAboutWelcome.test.jsx | 8 +- .../tests/unit}/OnboardingVideoTest.test.jsx | 2 +- .../aboutwelcome/tests/unit/unit-entry.js | 720 ++++++++++++++++++ browser/components/newtab/karma.mc.config.js | 34 - 23 files changed, 1339 insertions(+), 60 deletions(-) create mode 100644 browser/components/aboutwelcome/karma.mc.config.js rename browser/components/{newtab/lib => aboutwelcome/modules}/AWScreenUtils.jsm (99%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/AWScreenUtils.test.jsx (95%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/CTAParagraph.test.jsx (93%) rename browser/components/{newtab/test/unit/content-src/components => aboutwelcome/tests/unit}/HelpText.test.jsx (89%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/HeroImage.test.jsx (93%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/LinkParagraph.test.jsx (96%) create mode 100644 browser/components/aboutwelcome/tests/unit/MRColorways.test.jsx rename browser/components/{newtab/test/unit/content-src/components => aboutwelcome/tests/unit}/MSLocalized.test.jsx (94%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/MobileDownloads.test.jsx (93%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/MultiSelect.test.jsx (98%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/MultiStageAWProton.test.jsx (98%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/MultiStageAboutWelcome.test.jsx (98%) rename browser/components/{newtab/test/unit/aboutwelcome => aboutwelcome/tests/unit}/OnboardingVideoTest.test.jsx (92%) create mode 100644 browser/components/aboutwelcome/tests/unit/unit-entry.js diff --git a/browser/components/aboutwelcome/actors/AboutWelcomeParent.sys.mjs b/browser/components/aboutwelcome/actors/AboutWelcomeParent.sys.mjs index fb50b210ed55..41d102f5b837 100644 --- a/browser/components/aboutwelcome/actors/AboutWelcomeParent.sys.mjs +++ b/browser/components/aboutwelcome/actors/AboutWelcomeParent.sys.mjs @@ -22,7 +22,8 @@ XPCOMUtils.defineLazyModuleGetters(lazy, { "resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm", AboutWelcomeDefaults: "resource://activity-stream/aboutwelcome/lib/AboutWelcomeDefaults.jsm", - AWScreenUtils: "resource://activity-stream/lib/AWScreenUtils.jsm", + AWScreenUtils: + "resource://activity-stream/aboutwelcome/lib/AWScreenUtils.jsm", }); XPCOMUtils.defineLazyGetter(lazy, "log", () => { diff --git a/browser/components/aboutwelcome/content-src/components/HelpText.jsx b/browser/components/aboutwelcome/content-src/components/HelpText.jsx index a9dcca8c8e89..10f7463f0246 100644 --- a/browser/components/aboutwelcome/content-src/components/HelpText.jsx +++ b/browser/components/aboutwelcome/content-src/components/HelpText.jsx @@ -4,7 +4,7 @@ import React from "react"; import { Localized } from "./MSLocalized"; -import { AboutWelcomeUtils } from "../../lib/aboutwelcome-utils"; +import { AboutWelcomeUtils } from "../lib/aboutwelcome-utils"; const MS_STRING_PROP = "string_id"; export const HelpText = props => { diff --git a/browser/components/aboutwelcome/karma.mc.config.js b/browser/components/aboutwelcome/karma.mc.config.js new file mode 100644 index 000000000000..f9ef16da5e96 --- /dev/null +++ b/browser/components/aboutwelcome/karma.mc.config.js @@ -0,0 +1,243 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const path = require("path"); +const webpack = require("webpack"); +const { ResourceUriPlugin } = require("../newtab/tools/resourceUriPlugin"); + +const PATHS = { + // Where is the entry point for the unit tests? + testEntryFile: path.resolve(__dirname, "./tests/unit/unit-entry.js"), + + // A glob-style pattern matching all unit tests + testFilesPattern: "./tests/unit/unit-entry.js", + + // The base directory of all source files (used for path resolution in webpack importing) + moduleResolveDirectory: __dirname, + newtabResolveDirectory: "../newtab", + + // a RegEx matching all Cu.import statements of local files + resourcePathRegEx: /^resource:\/\/activity-stream\//, + + coverageReportingPath: "logs/coverage/", +}; + +// When tweaking here, be sure to review the docs about the execution ordering +// semantics of the preprocessors array, as they are somewhat odd. +const preprocessors = {}; +preprocessors[PATHS.testFilesPattern] = [ + "webpack", // require("karma-webpack") + "sourcemap", // require("karma-sourcemap-loader") +]; + +module.exports = function (config) { + const isTDD = config.tdd; + const browsers = isTDD ? ["Firefox"] : ["FirefoxHeadless"]; // require("karma-firefox-launcher") + config.set({ + singleRun: !isTDD, + browsers, + customLaunchers: { + FirefoxHeadless: { + base: "Firefox", + flags: ["--headless"], + }, + }, + frameworks: [ + "chai", // require("chai") require("karma-chai") + "mocha", // require("mocha") require("karma-mocha") + "sinon", // require("sinon") require("karma-sinon") + ], + reporters: [ + "coverage-istanbul", // require("karma-coverage") + "mocha", // require("karma-mocha-reporter") + + // for bin/try-runner.js to parse the output easily + "json", // require("karma-json-reporter") + ], + jsonReporter: { + // So this doesn't get interleaved with other karma output + stdout: false, + outputFile: path.join("logs", "karma-run-results.json"), + }, + coverageIstanbulReporter: { + reports: ["lcov", "text-summary"], // for some reason "lcov" reallys means "lcov" and "html" + "report-config": { + // so the full m-c path gets printed; needed for https://coverage.moz.tools/ integration + lcov: { + projectRoot: "../../..", + }, + }, + dir: PATHS.coverageReportingPath, + // This will make karma fail if coverage reporting is less than the minimums here + thresholds: !isTDD && { + each: { + statements: 100, + lines: 100, + functions: 100, + branches: 66, + overrides: { + "modules/*.jsm": { + statements: 0, + lines: 0, + functions: 0, + branches: 0, + }, + "content-src/lib/aboutwelcome-utils.js": { + statements: 50, + lines: 50, + functions: 50, + branches: 0, + }, + "content-src/components/LanguageSwitcher.jsx": { + // This file is covered by the mochitest: browser_aboutwelcome_multistage_languageSwitcher.js + statements: 0, + lines: 0, + functions: 0, + branches: 0, + }, + "content-src/components/EmbeddedMigrationWizard.jsx": { + // This file is covered by the mochitest: browser_aboutwelcome_multistage_mr.js + // Can't be unit tested because it relies on the migration-wizard custom element + statements: 0, + lines: 0, + functions: 0, + branches: 0, + }, + "content-src/components/AddonsPicker.jsx": { + // This file is covered by the mochitest: browser_aboutwelcome_multistage_addonspicker.js + statements: 0, + lines: 0, + functions: 0, + branches: 0, + }, + "content-src/**/*.jsx": { + statements: 62, + lines: 60, + functions: 50, + branches: 50, + }, + "content-src/components/**/*.jsx": { + statements: 51.1, + lines: 52.38, + functions: 31.2, + branches: 31.2, + }, + }, + }, + }, + }, + files: [PATHS.testEntryFile], + preprocessors, + webpack: { + mode: "none", + devtool: "inline-source-map", + // This loader allows us to override required files in tests + resolveLoader: { + alias: { + inject: path.join(__dirname, "../newtab/loaders/inject-loader"), + }, + }, + // This resolve config allows us to import with paths relative to the root directory, e.g. "lib/ActivityStream.jsm" + resolve: { + extensions: [".js", ".jsx"], + modules: [ + PATHS.moduleResolveDirectory, + "node_modules", + PATHS.newtabResolveDirectory, + ], + fallback: { + stream: require.resolve("stream-browserify"), + buffer: require.resolve("buffer"), + }, + alias: { + newtab: path.join(__dirname, "../newtab"), + }, + }, + plugins: [ + // The ResourceUriPlugin handles translating resource URIs in import + // statements in .mjs files, in a similar way to what + // babel-jsm-to-commonjs does for jsm files. + new ResourceUriPlugin({ + resourcePathRegEx: PATHS.resourcePathRegEx, + }), + new webpack.DefinePlugin({ + "process.env.NODE_ENV": JSON.stringify("development"), + }), + ], + externals: { + // enzyme needs these for backwards compatibility with 0.13. + // see https://github.com/airbnb/enzyme/blob/master/docs/guides/webpack.md#using-enzyme-with-webpack + "react/addons": true, + "react/lib/ReactContext": true, + "react/lib/ExecutionEnvironment": true, + }, + module: { + rules: [ + // This rule rewrites importing/exporting in .jsm files to be compatible with esmodules + { + test: /\.jsm$/, + exclude: [/node_modules/], + use: [ + { + loader: "babel-loader", // require("babel-core") + options: { + plugins: [ + // Converts .jsm files into common-js modules + [ + "../newtab/tools/babel-jsm-to-commonjs.js", + { + basePath: PATHS.resourcePathRegEx, + removeOtherImports: true, + replace: true, + }, + ], + "@babel/plugin-proposal-nullish-coalescing-operator", + "@babel/plugin-proposal-optional-chaining", + "@babel/plugin-proposal-class-properties", + ], + }, + }, + ], + }, + { + test: /\.js$/, + exclude: [/node_modules\/(?!@fluent\/).*/, /tests/], + loader: "babel-loader", + options: { + // This is a workaround for bug 1787278. It can be removed once + // that bug is fixed. + plugins: ["@babel/plugin-proposal-optional-chaining"], + }, + }, + { + test: /\.jsx$/, + exclude: /node_modules/, + loader: "babel-loader", + options: { + presets: ["@babel/preset-react"], + plugins: [ + "@babel/plugin-proposal-nullish-coalescing-operator", + "@babel/plugin-proposal-optional-chaining", + ], + }, + }, + { + test: /\.md$/, + use: "raw-loader", + }, + { + enforce: "post", + test: /\.js[mx]?$/, + loader: "@jsdevtools/coverage-istanbul-loader", + options: { esModules: true }, + include: [path.resolve("content-src"), path.resolve("modules")], + exclude: [path.resolve("tests"), path.resolve("../newtab")], + }, + ], + }, + }, + // Silences some overly-verbose logging of individual module builds + webpackMiddleware: { noInfo: true }, + }); +}; diff --git a/browser/components/newtab/lib/AWScreenUtils.jsm b/browser/components/aboutwelcome/modules/AWScreenUtils.jsm similarity index 99% rename from browser/components/newtab/lib/AWScreenUtils.jsm rename to browser/components/aboutwelcome/modules/AWScreenUtils.jsm index 93da92f630f2..018c67a40a6d 100644 --- a/browser/components/newtab/lib/AWScreenUtils.jsm +++ b/browser/components/aboutwelcome/modules/AWScreenUtils.jsm @@ -30,6 +30,7 @@ const AWScreenUtils = { /** * Given a JEXL expression, returns the evaluation of the expression or returns * true if the expression did not evaluate successfully + * * @param {string} targeting - The JEXL expression that will be evaluated * @returns {boolean} */ diff --git a/browser/components/aboutwelcome/modules/AboutWelcomeDefaults.jsm b/browser/components/aboutwelcome/modules/AboutWelcomeDefaults.jsm index 2210fa23b89d..9ea828106d07 100644 --- a/browser/components/aboutwelcome/modules/AboutWelcomeDefaults.jsm +++ b/browser/components/aboutwelcome/modules/AboutWelcomeDefaults.jsm @@ -21,7 +21,8 @@ ChromeUtils.defineESModuleGetters(lazy, { }); XPCOMUtils.defineLazyModuleGetters(lazy, { - AWScreenUtils: "resource://activity-stream/lib/AWScreenUtils.jsm", + AWScreenUtils: + "resource://activity-stream/aboutwelcome/lib/AWScreenUtils.jsm", }); // Message to be updated based on finalized MR designs diff --git a/browser/components/aboutwelcome/package.json b/browser/components/aboutwelcome/package.json index 4ebd39f9d29e..3693cc5897cb 100644 --- a/browser/components/aboutwelcome/package.json +++ b/browser/components/aboutwelcome/package.json @@ -13,12 +13,31 @@ "redux": "4.1.2" }, "devDependencies": { + "@babel/plugin-proposal-class-properties": "7.16.0", "@babel/plugin-proposal-optional-chaining": "7.16.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.0", "@babel/preset-react": "7.16.0", + "@jsdevtools/coverage-istanbul-loader": "^3.0.5", "babel-loader": "8.2.3", + "babel-plugin-jsm-to-esmodules": "0.6.0", + "chai": "4.3.4", + "chai-json-schema": "1.5.1", + "enzyme": "3.11.0", + "enzyme-adapter-react-16": "1.15.6", + "karma": "6.3.8", + "karma-chai": "0.1.0", + "karma-coverage-istanbul-reporter": "3.0.3", + "karma-firefox-launcher": "2.1.2", + "karma-json-reporter": "1.2.1", + "karma-mocha": "2.0.1", + "karma-mocha-reporter": "2.2.5", + "karma-sinon": "1.0.5", + "karma-sourcemap-loader": "0.3.8", + "karma-webpack": "5.0.0", "npm-run-all": "4.1.5", "sass": "1.43.4", "sinon": "12.0.1", + "stream-browserify": "3.0.0", "webpack": "5.56.0", "webpack-cli": "4.9.1", "yamscripts": "0.1.0" diff --git a/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_addonspicker.js b/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_addonspicker.js index 9c4b7b36cdd3..e5465525f3a4 100644 --- a/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_addonspicker.js +++ b/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_addonspicker.js @@ -8,7 +8,7 @@ const { AboutWelcomeTelemetry } = ChromeUtils.import( "resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm" ); const { AWScreenUtils } = ChromeUtils.import( - "resource://activity-stream/lib/AWScreenUtils.jsm" + "resource://activity-stream/aboutwelcome/lib/AWScreenUtils.jsm" ); const { InternalTestingProfileMigrator } = ChromeUtils.importESModule( "resource:///modules/InternalTestingProfileMigrator.sys.mjs" diff --git a/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_languageSwitcher.js b/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_languageSwitcher.js index cd77d90de882..f8e8899af1d2 100644 --- a/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_languageSwitcher.js +++ b/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_languageSwitcher.js @@ -5,7 +5,7 @@ const { getAddonAndLocalAPIsMocker } = ChromeUtils.importESModule( ); const { AWScreenUtils } = ChromeUtils.import( - "resource://activity-stream/lib/AWScreenUtils.jsm" + "resource://activity-stream/aboutwelcome/lib/AWScreenUtils.jsm" ); const sandbox = sinon.createSandbox(); diff --git a/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_mr.js b/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_mr.js index ee867a11d992..3d12e827d8d5 100644 --- a/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_mr.js +++ b/browser/components/aboutwelcome/tests/browser/browser_aboutwelcome_multistage_mr.js @@ -8,7 +8,7 @@ const { AboutWelcomeTelemetry } = ChromeUtils.import( "resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm" ); const { AWScreenUtils } = ChromeUtils.import( - "resource://activity-stream/lib/AWScreenUtils.jsm" + "resource://activity-stream/aboutwelcome/lib/AWScreenUtils.jsm" ); const { InternalTestingProfileMigrator } = ChromeUtils.importESModule( "resource:///modules/InternalTestingProfileMigrator.sys.mjs" diff --git a/browser/components/newtab/test/unit/aboutwelcome/AWScreenUtils.test.jsx b/browser/components/aboutwelcome/tests/unit/AWScreenUtils.test.jsx similarity index 95% rename from browser/components/newtab/test/unit/aboutwelcome/AWScreenUtils.test.jsx rename to browser/components/aboutwelcome/tests/unit/AWScreenUtils.test.jsx index a9f401f6b753..4f347a04f320 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/AWScreenUtils.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/AWScreenUtils.test.jsx @@ -1,6 +1,6 @@ -import { AWScreenUtils } from "lib/AWScreenUtils.jsm"; -import { GlobalOverrider } from "test/unit/utils"; -import { ASRouter } from "lib/ASRouter.jsm"; +import { AWScreenUtils } from "modules/AWScreenUtils.jsm"; +import { GlobalOverrider } from "newtab/test/unit/utils"; +import { ASRouter } from "newtab/lib/ASRouter.jsm"; describe("AWScreenUtils", () => { let sandbox; diff --git a/browser/components/newtab/test/unit/aboutwelcome/CTAParagraph.test.jsx b/browser/components/aboutwelcome/tests/unit/CTAParagraph.test.jsx similarity index 93% rename from browser/components/newtab/test/unit/aboutwelcome/CTAParagraph.test.jsx rename to browser/components/aboutwelcome/tests/unit/CTAParagraph.test.jsx index 57773b0e82e4..c60e8e2666c4 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/CTAParagraph.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/CTAParagraph.test.jsx @@ -1,6 +1,6 @@ import React from "react"; import { shallow } from "enzyme"; -import { CTAParagraph } from "content-src/aboutwelcome/components/CTAParagraph"; +import { CTAParagraph } from "content-src/components/CTAParagraph"; describe("CTAParagraph component", () => { let sandbox; diff --git a/browser/components/newtab/test/unit/content-src/components/HelpText.test.jsx b/browser/components/aboutwelcome/tests/unit/HelpText.test.jsx similarity index 89% rename from browser/components/newtab/test/unit/content-src/components/HelpText.test.jsx rename to browser/components/aboutwelcome/tests/unit/HelpText.test.jsx index e2cf4f1f21e0..e9b722b9d8f4 100644 --- a/browser/components/newtab/test/unit/content-src/components/HelpText.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/HelpText.test.jsx @@ -1,5 +1,5 @@ -import { HelpText } from "content-src/aboutwelcome/components/HelpText"; -import { Localized } from "content-src/aboutwelcome/components/MSLocalized"; +import { HelpText } from "content-src/components/HelpText"; +import { Localized } from "content-src/components/MSLocalized"; import React from "react"; import { shallow } from "enzyme"; diff --git a/browser/components/newtab/test/unit/aboutwelcome/HeroImage.test.jsx b/browser/components/aboutwelcome/tests/unit/HeroImage.test.jsx similarity index 93% rename from browser/components/newtab/test/unit/aboutwelcome/HeroImage.test.jsx rename to browser/components/aboutwelcome/tests/unit/HeroImage.test.jsx index 8c9bdc8e50c7..244e64f906ed 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/HeroImage.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/HeroImage.test.jsx @@ -1,6 +1,6 @@ import React from "react"; import { shallow } from "enzyme"; -import { HeroImage } from "content-src/aboutwelcome/components/HeroImage"; +import { HeroImage } from "content-src/components/HeroImage"; describe("HeroImage component", () => { const imageUrl = "https://example.com"; diff --git a/browser/components/newtab/test/unit/aboutwelcome/LinkParagraph.test.jsx b/browser/components/aboutwelcome/tests/unit/LinkParagraph.test.jsx similarity index 96% rename from browser/components/newtab/test/unit/aboutwelcome/LinkParagraph.test.jsx rename to browser/components/aboutwelcome/tests/unit/LinkParagraph.test.jsx index 35f56fe06756..821ed765d3ce 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/LinkParagraph.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/LinkParagraph.test.jsx @@ -1,6 +1,6 @@ import React from "react"; import { mount } from "enzyme"; -import { LinkParagraph } from "../../../content-src/aboutwelcome/components/LinkParagraph"; +import { LinkParagraph } from "content-src/components/LinkParagraph"; describe("LinkParagraph component", () => { let sandbox; diff --git a/browser/components/aboutwelcome/tests/unit/MRColorways.test.jsx b/browser/components/aboutwelcome/tests/unit/MRColorways.test.jsx new file mode 100644 index 000000000000..2d9ebf7ec9b3 --- /dev/null +++ b/browser/components/aboutwelcome/tests/unit/MRColorways.test.jsx @@ -0,0 +1,328 @@ +import React from "react"; +import { shallow } from "enzyme"; +import { + Colorways, + computeColorWay, + ColorwayDescription, + computeVariationIndex, +} from "content-src/components/MRColorways"; +import { WelcomeScreen } from "content-src/components/MultiStageAboutWelcome"; + +describe("Multistage AboutWelcome module", () => { + let sandbox; + let COLORWAY_SCREEN_PROPS; + beforeEach(() => { + sandbox = sinon.createSandbox(); + COLORWAY_SCREEN_PROPS = { + id: "test-colorway-screen", + totalNumberofScreens: 1, + content: { + subtitle: "test subtitle", + tiles: { + type: "colorway", + action: { + theme: "", + }, + defaultVariationIndex: 0, + systemVariations: ["automatic", "light"], + variations: ["soft", "bold"], + colorways: [ + { + id: "default", + label: "Default", + }, + { + id: "abstract", + label: "Abstract", + }, + ], + }, + primary_button: { + action: {}, + label: "test button", + }, + }, + messageId: "test-mr-colorway-screen", + activeTheme: "automatic", + }; + }); + afterEach(() => { + sandbox.restore(); + }); + + describe("MRColorway component", () => { + it("should render WelcomeScreen", () => { + const wrapper = shallow(); + + assert.ok(wrapper.exists()); + }); + + it("should use default when activeTheme is not set", () => { + const wrapper = shallow(); + wrapper.setProps({ activeTheme: null }); + + const colorwaysOptionIcons = wrapper.find( + ".tiles-theme-section .theme .icon" + ); + assert.strictEqual(colorwaysOptionIcons.length, 2); + + // Default automatic theme is selected by default + assert.strictEqual( + colorwaysOptionIcons.first().prop("className").includes("selected"), + true + ); + + assert.strictEqual( + colorwaysOptionIcons.first().prop("className").includes("default"), + true + ); + }); + + it("should use default when activeTheme is alpenglow", () => { + const wrapper = shallow(); + wrapper.setProps({ activeTheme: "alpenglow" }); + + const colorwaysOptionIcons = wrapper.find( + ".tiles-theme-section .theme .icon" + ); + assert.strictEqual(colorwaysOptionIcons.length, 2); + + // Default automatic theme is selected when unsupported in colorway alpenglow theme is active + assert.strictEqual( + colorwaysOptionIcons.first().prop("className").includes("selected"), + true + ); + + assert.strictEqual( + colorwaysOptionIcons.first().prop("className").includes("default"), + true + ); + }); + + it("should render colorways options", () => { + const wrapper = shallow(); + + const colorwaysOptions = wrapper.find( + ".tiles-theme-section .theme input[name='theme']" + ); + + const colorwaysOptionIcons = wrapper.find( + ".tiles-theme-section .theme .icon" + ); + + const colorwaysLabels = wrapper.find( + ".tiles-theme-section .theme span.sr-only" + ); + + assert.strictEqual(colorwaysOptions.length, 2); + assert.strictEqual(colorwaysOptionIcons.length, 2); + assert.strictEqual(colorwaysLabels.length, 2); + + // First colorway option + // Default theme radio option is selected by default + assert.strictEqual( + colorwaysOptionIcons.first().prop("className").includes("selected"), + true + ); + + //Colorway should be using id property + assert.strictEqual( + colorwaysOptions.first().prop("data-colorway"), + "default" + ); + + // Second colorway option + assert.strictEqual( + colorwaysOptionIcons.last().prop("className").includes("selected"), + false + ); + + //Colorway should be using id property + assert.strictEqual( + colorwaysOptions.last().prop("data-colorway"), + "abstract" + ); + + //Colorway should be labelled for screen readers (parent label is for tooltip only, and does not describe the Colorway) + assert.strictEqual( + colorwaysOptions.last().prop("aria-labelledby"), + "abstract-label" + ); + }); + + it("should handle colorway clicks", () => { + sandbox.stub(React, "useEffect").callsFake((fn, vals) => { + if (vals === undefined) { + fn(); + } else if (vals[0] === "in") { + fn(); + } + }); + + const handleAction = sandbox.stub(); + const wrapper = shallow( + + ); + const colorwaysOptions = wrapper.find( + ".tiles-theme-section .theme input[name='theme']" + ); + + let props = wrapper.find(ColorwayDescription).props(); + assert.propertyVal(props.colorway, "label", "Default"); + + const option = colorwaysOptions.last(); + assert.propertyVal(option.props(), "value", "abstract-soft"); + colorwaysOptions.last().simulate("click"); + assert.calledOnce(handleAction); + }); + + it("should render colorway description", () => { + const wrapper = shallow(); + + let descriptionsWrapper = wrapper.find(ColorwayDescription); + assert.ok(descriptionsWrapper.exists()); + + let props = descriptionsWrapper.props(); + + // Colorway description should display Default theme desc by default + assert.strictEqual(props.colorway.label, "Default"); + }); + + it("ColorwayDescription should display active colorway desc", () => { + let TEST_COLORWAY_PROPS = { + colorway: { + label: "Activist", + description: "Test Activist", + }, + }; + const descWrapper = shallow( + + ); + assert.ok(descWrapper.exists()); + const descText = descWrapper.find(".colorway-text"); + assert.equal( + descText.props()["data-l10n-args"].includes("Activist"), + true + ); + }); + + it("should computeColorWayId for default active theme", () => { + let TEST_COLORWAY_PROPS = { + ...COLORWAY_SCREEN_PROPS, + }; + + const colorwayId = computeColorWay( + TEST_COLORWAY_PROPS.activeTheme, + TEST_COLORWAY_PROPS.content.tiles.systemVariations + ); + assert.strictEqual(colorwayId, "default"); + }); + + it("should computeColorWayId for non-default active theme", () => { + let TEST_COLORWAY_PROPS = { + ...COLORWAY_SCREEN_PROPS, + activeTheme: "abstract-soft", + }; + + const colorwayId = computeColorWay( + TEST_COLORWAY_PROPS.activeTheme, + TEST_COLORWAY_PROPS.content.tiles.systemVariations + ); + assert.strictEqual(colorwayId, "abstract"); + }); + + it("should computeVariationIndex for default active theme", () => { + let TEST_COLORWAY_PROPS = { + ...COLORWAY_SCREEN_PROPS, + }; + + const variationIndex = computeVariationIndex( + TEST_COLORWAY_PROPS.activeTheme, + TEST_COLORWAY_PROPS.content.tiles.systemVariations, + TEST_COLORWAY_PROPS.content.tiles.variations, + TEST_COLORWAY_PROPS.content.tiles.defaultVariationIndex + ); + assert.strictEqual( + variationIndex, + TEST_COLORWAY_PROPS.content.tiles.defaultVariationIndex + ); + }); + + it("should computeVariationIndex for active theme", () => { + let TEST_COLORWAY_PROPS = { + ...COLORWAY_SCREEN_PROPS, + }; + + const variationIndex = computeVariationIndex( + "light", + TEST_COLORWAY_PROPS.content.tiles.systemVariations, + TEST_COLORWAY_PROPS.content.tiles.variations, + TEST_COLORWAY_PROPS.content.tiles.defaultVariationIndex + ); + assert.strictEqual(variationIndex, 1); + }); + + it("should computeVariationIndex for colorway theme", () => { + let TEST_COLORWAY_PROPS = { + ...COLORWAY_SCREEN_PROPS, + }; + + const variationIndex = computeVariationIndex( + "abstract-bold", + TEST_COLORWAY_PROPS.content.tiles.systemVariations, + TEST_COLORWAY_PROPS.content.tiles.variations, + TEST_COLORWAY_PROPS.content.tiles.defaultVariationIndex + ); + assert.strictEqual(variationIndex, 1); + }); + + describe("random colorways", () => { + let test; + beforeEach(() => { + COLORWAY_SCREEN_PROPS.handleAction = sandbox.stub(); + sandbox.stub(window, "matchMedia"); + // eslint-disable-next-line max-nested-callbacks + sandbox.stub(React, "useEffect").callsFake((fn, vals) => { + if (vals?.length === 0) { + fn(); + } + }); + test = () => { + shallow(); + return COLORWAY_SCREEN_PROPS.handleAction.firstCall.firstArg + .currentTarget; + }; + }); + + it("should select a random colorway", () => { + const { value } = test(); + + assert.strictEqual(value, "abstract-soft"); + assert.calledThrice(React.useEffect); + assert.notCalled(window.matchMedia); + }); + + it("should select a random soft colorway when not dark", () => { + window.matchMedia.returns({ matches: false }); + COLORWAY_SCREEN_PROPS.content.tiles.darkVariation = 1; + + const { value } = test(); + + assert.strictEqual(value, "abstract-soft"); + assert.calledThrice(React.useEffect); + assert.calledOnce(window.matchMedia); + }); + + it("should select a random bold colorway when dark", () => { + window.matchMedia.returns({ matches: true }); + COLORWAY_SCREEN_PROPS.content.tiles.darkVariation = 1; + + const { value } = test(); + + assert.strictEqual(value, "abstract-bold"); + assert.calledThrice(React.useEffect); + assert.calledOnce(window.matchMedia); + }); + }); + }); +}); diff --git a/browser/components/newtab/test/unit/content-src/components/MSLocalized.test.jsx b/browser/components/aboutwelcome/tests/unit/MSLocalized.test.jsx similarity index 94% rename from browser/components/newtab/test/unit/content-src/components/MSLocalized.test.jsx rename to browser/components/aboutwelcome/tests/unit/MSLocalized.test.jsx index d46f794513b4..57f7e5526c0d 100644 --- a/browser/components/newtab/test/unit/content-src/components/MSLocalized.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/MSLocalized.test.jsx @@ -1,4 +1,4 @@ -import { Localized } from "content-src/aboutwelcome/components/MSLocalized"; +import { Localized } from "content-src/components/MSLocalized"; import React from "react"; import { shallow } from "enzyme"; diff --git a/browser/components/newtab/test/unit/aboutwelcome/MobileDownloads.test.jsx b/browser/components/aboutwelcome/tests/unit/MobileDownloads.test.jsx similarity index 93% rename from browser/components/newtab/test/unit/aboutwelcome/MobileDownloads.test.jsx rename to browser/components/aboutwelcome/tests/unit/MobileDownloads.test.jsx index e3ed5d2bb083..143c7d2f8d43 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/MobileDownloads.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/MobileDownloads.test.jsx @@ -1,7 +1,7 @@ import React from "react"; import { shallow, mount } from "enzyme"; -import { GlobalOverrider } from "test/unit/utils"; -import { MobileDownloads } from "content-src/aboutwelcome/components/MobileDownloads"; +import { GlobalOverrider } from "newtab/test/unit/utils"; +import { MobileDownloads } from "content-src/components/MobileDownloads"; describe("Multistage AboutWelcome MobileDownloads module", () => { let globals; diff --git a/browser/components/newtab/test/unit/aboutwelcome/MultiSelect.test.jsx b/browser/components/aboutwelcome/tests/unit/MultiSelect.test.jsx similarity index 98% rename from browser/components/newtab/test/unit/aboutwelcome/MultiSelect.test.jsx rename to browser/components/aboutwelcome/tests/unit/MultiSelect.test.jsx index 56c5c7f3935e..5fbe9c04061e 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/MultiSelect.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/MultiSelect.test.jsx @@ -1,6 +1,6 @@ import React from "react"; import { mount } from "enzyme"; -import { MultiSelect } from "content-src/aboutwelcome/components/MultiSelect"; +import { MultiSelect } from "content-src/components/MultiSelect"; describe("Multistage AboutWelcome module", () => { let sandbox; diff --git a/browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx b/browser/components/aboutwelcome/tests/unit/MultiStageAWProton.test.jsx similarity index 98% rename from browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx rename to browser/components/aboutwelcome/tests/unit/MultiStageAWProton.test.jsx index bc3b0cd18eaa..1cfe9480d055 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/MultiStageAWProton.test.jsx @@ -1,6 +1,6 @@ -import { AboutWelcomeDefaults } from "aboutwelcome/lib/AboutWelcomeDefaults.jsm"; -import { MultiStageProtonScreen } from "content-src/aboutwelcome/components/MultiStageProtonScreen"; -import { AWScreenUtils } from "lib/AWScreenUtils.jsm"; +import { AboutWelcomeDefaults } from "modules/AboutWelcomeDefaults.jsm"; +import { MultiStageProtonScreen } from "content-src/components/MultiStageProtonScreen"; +import { AWScreenUtils } from "modules/AWScreenUtils.jsm"; import React from "react"; import { mount } from "enzyme"; diff --git a/browser/components/newtab/test/unit/aboutwelcome/MultiStageAboutWelcome.test.jsx b/browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx similarity index 98% rename from browser/components/newtab/test/unit/aboutwelcome/MultiStageAboutWelcome.test.jsx rename to browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx index 3a9367a23143..ed20e0ed618b 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/MultiStageAboutWelcome.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx @@ -1,15 +1,15 @@ -import { GlobalOverrider } from "test/unit/utils"; +import { GlobalOverrider } from "newtab/test/unit/utils"; import { MultiStageAboutWelcome, SecondaryCTA, StepsIndicator, ProgressBar, WelcomeScreen, -} from "content-src/aboutwelcome/components/MultiStageAboutWelcome"; -import { Themes } from "content-src/aboutwelcome/components/Themes"; +} from "content-src/components/MultiStageAboutWelcome"; +import { Themes } from "content-src/components/Themes"; import React from "react"; import { shallow, mount } from "enzyme"; -import { AboutWelcomeDefaults } from "aboutwelcome/lib/AboutWelcomeDefaults.jsm"; +import { AboutWelcomeDefaults } from "modules/AboutWelcomeDefaults.jsm"; import { AboutWelcomeUtils } from "content-src/lib/aboutwelcome-utils"; describe("MultiStageAboutWelcome module", () => { diff --git a/browser/components/newtab/test/unit/aboutwelcome/OnboardingVideoTest.test.jsx b/browser/components/aboutwelcome/tests/unit/OnboardingVideoTest.test.jsx similarity index 92% rename from browser/components/newtab/test/unit/aboutwelcome/OnboardingVideoTest.test.jsx rename to browser/components/aboutwelcome/tests/unit/OnboardingVideoTest.test.jsx index db6d8ba10abe..078c8e17c4ae 100644 --- a/browser/components/newtab/test/unit/aboutwelcome/OnboardingVideoTest.test.jsx +++ b/browser/components/aboutwelcome/tests/unit/OnboardingVideoTest.test.jsx @@ -1,6 +1,6 @@ import React from "react"; import { mount } from "enzyme"; -import { OnboardingVideo } from "content-src/aboutwelcome/components/OnboardingVideo"; +import { OnboardingVideo } from "content-src/components/OnboardingVideo"; describe("OnboardingVideo component", () => { let sandbox; diff --git a/browser/components/aboutwelcome/tests/unit/unit-entry.js b/browser/components/aboutwelcome/tests/unit/unit-entry.js new file mode 100644 index 000000000000..8f59a230960f --- /dev/null +++ b/browser/components/aboutwelcome/tests/unit/unit-entry.js @@ -0,0 +1,720 @@ +import { + EventEmitter, + FakePrefs, + FakensIPrefService, + GlobalOverrider, + FakeConsoleAPI, + FakeLogger, +} from "newtab/test/unit/utils"; +import Adapter from "enzyme-adapter-react-16"; +import { chaiAssertions } from "newtab/test/schemas/pings"; +import chaiJsonSchema from "chai-json-schema"; +import enzyme from "enzyme"; +import FxMSCommonSchema from "newtab/content-src/asrouter/schemas/FxMSCommon.schema.json"; + +enzyme.configure({ adapter: new Adapter() }); + +// Cause React warnings to make tests that trigger them fail +const origConsoleError = console.error; +console.error = function (msg, ...args) { + origConsoleError.apply(console, [msg, ...args]); + + if ( + /(Invalid prop|Failed prop type|Check the render method|React Intl)/.test( + msg + ) + ) { + throw new Error(msg); + } +}; + +const req = require.context(".", true, /\.test\.jsx?$/); +const files = req.keys(); + +// This exposes sinon assertions to chai.assert +sinon.assert.expose(assert, { prefix: "" }); + +chai.use(chaiAssertions); +chai.use(chaiJsonSchema); +chai.tv4.addSchema("file:///FxMSCommon.schema.json", FxMSCommonSchema); + +const overrider = new GlobalOverrider(); + +const RemoteSettings = name => ({ + get: () => { + if (name === "attachment") { + return Promise.resolve([{ attachment: {} }]); + } + return Promise.resolve([]); + }, + on: () => {}, + off: () => {}, +}); +RemoteSettings.pollChanges = () => {}; + +class JSWindowActorParent { + sendAsyncMessage(name, data) { + return { name, data }; + } +} + +class JSWindowActorChild { + sendAsyncMessage(name, data) { + return { name, data }; + } + + sendQuery(name, data) { + return Promise.resolve({ name, data }); + } + + get contentWindow() { + return { + Promise, + }; + } +} + +// Detect plain object passed to lazy getter APIs, and set its prototype to +// global object, and return the global object for further modification. +// Returns the object if it's not plain object. +// +// This is a workaround to make the existing testharness and testcase keep +// working even after lazy getters are moved to plain `lazy` object. +const cachedPlainObject = new Set(); +function updateGlobalOrObject(object) { + // Given this function modifies the prototype, and the following + // condition doesn't meet on the second call, cache the result. + if (cachedPlainObject.has(object)) { + return global; + } + + if (Object.getPrototypeOf(object).constructor.name !== "Object") { + return object; + } + + cachedPlainObject.add(object); + Object.setPrototypeOf(object, global); + return global; +} + +const TEST_GLOBAL = { + JSWindowActorParent, + JSWindowActorChild, + AboutReaderParent: { + addMessageListener: (messageName, listener) => {}, + removeMessageListener: (messageName, listener) => {}, + }, + AboutWelcomeTelemetry: class { + submitGleanPingForPing() {} + }, + AddonManager: { + getActiveAddons() { + return Promise.resolve({ addons: [], fullData: false }); + }, + }, + AppConstants: { + MOZILLA_OFFICIAL: true, + MOZ_APP_VERSION: "69.0a1", + isChinaRepack() { + return false; + }, + isPlatformAndVersionAtMost() { + return false; + }, + platform: "win", + }, + ASRouterPreferences: { + console: new FakeConsoleAPI({ + maxLogLevel: "off", // set this to "debug" or "all" to get more ASRouter logging in tests + prefix: "ASRouter", + }), + }, + AWScreenUtils: { + evaluateTargetingAndRemoveScreens() { + return true; + }, + async removeScreens() { + return true; + }, + evaluateScreenTargeting() { + return true; + }, + }, + BrowserUtils: { + sendToDeviceEmailsSupported() { + return true; + }, + }, + UpdateUtils: { getUpdateChannel() {} }, + BasePromiseWorker: class { + constructor() { + this.ExceptionHandlers = []; + } + post() {} + }, + browserSearchRegion: "US", + BrowserWindowTracker: { getTopWindow() {} }, + ChromeUtils: { + defineModuleGetter: updateGlobalOrObject, + defineESModuleGetters: updateGlobalOrObject, + generateQI() { + return {}; + }, + import() { + return global; + }, + importESModule() { + return global; + }, + }, + ClientEnvironment: { + get userId() { + return "foo123"; + }, + }, + Components: { + Constructor(classId) { + switch (classId) { + case "@mozilla.org/referrer-info;1": + return function (referrerPolicy, sendReferrer, originalReferrer) { + this.referrerPolicy = referrerPolicy; + this.sendReferrer = sendReferrer; + this.originalReferrer = originalReferrer; + }; + } + return function () {}; + }, + isSuccessCode: () => true, + }, + ConsoleAPI: FakeConsoleAPI, + // NB: These are functions/constructors + // eslint-disable-next-line object-shorthand + ContentSearchUIController: function () {}, + // eslint-disable-next-line object-shorthand + ContentSearchHandoffUIController: function () {}, + Cc: { + "@mozilla.org/browser/nav-bookmarks-service;1": { + addObserver() {}, + getService() { + return this; + }, + removeObserver() {}, + SOURCES: {}, + TYPE_BOOKMARK: {}, + }, + "@mozilla.org/browser/nav-history-service;1": { + addObserver() {}, + executeQuery() {}, + getNewQuery() {}, + getNewQueryOptions() {}, + getService() { + return this; + }, + insert() {}, + markPageAsTyped() {}, + removeObserver() {}, + }, + "@mozilla.org/io/string-input-stream;1": { + createInstance() { + return {}; + }, + }, + "@mozilla.org/security/hash;1": { + createInstance() { + return { + init() {}, + updateFromStream() {}, + finish() { + return "0"; + }, + }; + }, + }, + "@mozilla.org/updates/update-checker;1": { createInstance() {} }, + "@mozilla.org/widget/useridleservice;1": { + getService() { + return { + idleTime: 0, + addIdleObserver() {}, + removeIdleObserver() {}, + }; + }, + }, + "@mozilla.org/streamConverters;1": { + getService() { + return this; + }, + }, + "@mozilla.org/network/stream-loader;1": { + createInstance() { + return {}; + }, + }, + }, + Ci: { + nsICryptoHash: {}, + nsIReferrerInfo: { UNSAFE_URL: 5 }, + nsITimer: { TYPE_ONE_SHOT: 1 }, + nsIWebProgressListener: { LOCATION_CHANGE_SAME_DOCUMENT: 1 }, + nsIDOMWindow: Object, + nsITrackingDBService: { + TRACKERS_ID: 1, + TRACKING_COOKIES_ID: 2, + CRYPTOMINERS_ID: 3, + FINGERPRINTERS_ID: 4, + SOCIAL_ID: 5, + }, + nsICookieBannerService: { + MODE_DISABLED: 0, + MODE_REJECT: 1, + MODE_REJECT_OR_ACCEPT: 2, + MODE_UNSET: 3, + }, + }, + Cu: { + importGlobalProperties() {}, + now: () => window.performance.now(), + cloneInto: o => JSON.parse(JSON.stringify(o)), + }, + console: { + ...console, + error() {}, + }, + dump() {}, + EveryWindow: { + registerCallback: (id, init, uninit) => {}, + unregisterCallback: id => {}, + }, + setTimeout: window.setTimeout.bind(window), + clearTimeout: window.clearTimeout.bind(window), + fetch() {}, + // eslint-disable-next-line object-shorthand + Image: function () {}, // NB: This is a function/constructor + IOUtils: { + writeJSON() { + return Promise.resolve(0); + }, + readJSON() { + return Promise.resolve({}); + }, + read() { + return Promise.resolve(new Uint8Array()); + }, + makeDirectory() { + return Promise.resolve(0); + }, + write() { + return Promise.resolve(0); + }, + exists() { + return Promise.resolve(0); + }, + remove() { + return Promise.resolve(0); + }, + stat() { + return Promise.resolve(0); + }, + }, + NewTabUtils: { + activityStreamProvider: { + getTopFrecentSites: () => [], + executePlacesQuery: async (sql, options) => ({ sql, options }), + }, + }, + OS: { + File: { + writeAtomic() {}, + makeDir() {}, + stat() {}, + Error: {}, + read() {}, + exists() {}, + remove() {}, + removeEmptyDir() {}, + }, + Path: { + join() { + return "/"; + }, + }, + Constants: { + Path: { + localProfileDir: "/", + }, + }, + }, + PathUtils: { + join(...parts) { + return parts[parts.length - 1]; + }, + joinRelative(...parts) { + return parts[parts.length - 1]; + }, + getProfileDir() { + return Promise.resolve("/"); + }, + getLocalProfileDir() { + return Promise.resolve("/"); + }, + }, + PlacesUtils: { + get bookmarks() { + return TEST_GLOBAL.Cc["@mozilla.org/browser/nav-bookmarks-service;1"]; + }, + get history() { + return TEST_GLOBAL.Cc["@mozilla.org/browser/nav-history-service;1"]; + }, + observers: { + addListener() {}, + removeListener() {}, + }, + }, + Preferences: FakePrefs, + PrivateBrowsingUtils: { + isBrowserPrivate: () => false, + isWindowPrivate: () => false, + permanentPrivateBrowsing: false, + }, + DownloadsViewUI: { + getDisplayName: () => "filename.ext", + getSizeWithUnits: () => "1.5 MB", + }, + FileUtils: { + // eslint-disable-next-line object-shorthand + File: function () {}, // NB: This is a function/constructor + }, + Region: { + home: "US", + REGION_TOPIC: "browser-region-updated", + }, + Services: { + dirsvc: { + get: () => ({ parent: { parent: { path: "appPath" } } }), + }, + env: { + set: () => undefined, + }, + locale: { + get appLocaleAsBCP47() { + return "en-US"; + }, + negotiateLanguages() {}, + }, + urlFormatter: { formatURL: str => str, formatURLPref: str => str }, + mm: { + addMessageListener: (msg, cb) => this.receiveMessage(), + removeMessageListener() {}, + }, + obs: { + addObserver() {}, + removeObserver() {}, + notifyObservers() {}, + }, + telemetry: { + setEventRecordingEnabled: () => {}, + recordEvent: eventDetails => {}, + scalarSet: () => {}, + keyedScalarAdd: () => {}, + }, + uuid: { + generateUUID() { + return "{foo-123-foo}"; + }, + }, + console: { logStringMessage: () => {} }, + prefs: new FakensIPrefService(), + tm: { + dispatchToMainThread: cb => cb(), + idleDispatchToMainThread: cb => cb(), + }, + eTLD: { + getBaseDomain({ spec }) { + return spec.match(/\/([^/]+)/)[1]; + }, + getBaseDomainFromHost(host) { + return host.match(/.*?(\w+\.\w+)$/)[1]; + }, + getPublicSuffix() {}, + }, + io: { + newURI: spec => ({ + mutate: () => ({ + setRef: ref => ({ + finalize: () => ({ + ref, + spec, + }), + }), + }), + spec, + }), + }, + search: { + init() { + return Promise.resolve(); + }, + getVisibleEngines: () => + Promise.resolve([{ identifier: "google" }, { identifier: "bing" }]), + defaultEngine: { + identifier: "google", + searchForm: + "https://www.google.com/search?q=&ie=utf-8&oe=utf-8&client=firefox-b", + aliases: ["@google"], + }, + defaultPrivateEngine: { + identifier: "bing", + searchForm: "https://www.bing.com", + aliases: ["@bing"], + }, + getEngineByAlias: async () => null, + }, + scriptSecurityManager: { + createNullPrincipal() {}, + getSystemPrincipal() {}, + }, + wm: { + getMostRecentWindow: () => window, + getMostRecentBrowserWindow: () => window, + getEnumerator: () => [], + }, + ww: { registerNotification() {}, unregisterNotification() {} }, + appinfo: { appBuildID: "20180710100040", version: "69.0a1" }, + scriptloader: { loadSubScript: () => {} }, + startup: { + getStartupInfo() { + return { + process: { + getTime() { + return 1588010448000; + }, + }, + }; + }, + }, + }, + XPCOMUtils: { + defineLazyGetter(object, name, f) { + updateGlobalOrObject(object)[name] = f(); + }, + defineLazyGlobalGetters: updateGlobalOrObject, + defineLazyModuleGetters: updateGlobalOrObject, + defineLazyServiceGetter: updateGlobalOrObject, + defineLazyServiceGetters: updateGlobalOrObject, + defineLazyPreferenceGetter(object, name) { + updateGlobalOrObject(object)[name] = ""; + }, + generateQI() { + return {}; + }, + }, + EventEmitter, + ShellService: { + doesAppNeedPin: () => false, + isDefaultBrowser: () => true, + }, + FilterExpressions: { + eval() { + return Promise.resolve(false); + }, + }, + RemoteSettings, + Localization: class { + async formatMessages(stringsIds) { + return Promise.resolve( + stringsIds.map(({ id, args }) => ({ value: { string_id: id, args } })) + ); + } + async formatValue(stringId) { + return Promise.resolve(stringId); + } + }, + FxAccountsConfig: { + promiseConnectAccountURI(id) { + return Promise.resolve(id); + }, + }, + FX_MONITOR_OAUTH_CLIENT_ID: "fake_client_id", + ExperimentAPI: { + getExperiment() {}, + getExperimentMetaData() {}, + getRolloutMetaData() {}, + }, + NimbusFeatures: { + glean: { + getVariable() {}, + }, + newtab: { + getVariable() {}, + getAllVariables() {}, + onUpdate() {}, + offUpdate() {}, + }, + pocketNewtab: { + getVariable() {}, + getAllVariables() {}, + onUpdate() {}, + offUpdate() {}, + }, + cookieBannerHandling: { + getVariable() {}, + }, + }, + TelemetryEnvironment: { + setExperimentActive() {}, + currentEnvironment: { + profile: { + creationDate: 16587, + }, + settings: {}, + }, + }, + TelemetryStopwatch: { + start: () => {}, + finish: () => {}, + }, + Sampling: { + ratioSample(seed, ratios) { + return Promise.resolve(0); + }, + }, + BrowserHandler: { + get kiosk() { + return false; + }, + }, + TelemetrySession: { + getMetadata(reason) { + return { + reason, + sessionId: "fake_session_id", + }; + }, + }, + PageThumbs: { + addExpirationFilter() {}, + removeExpirationFilter() {}, + }, + Logger: FakeLogger, + getFxAccountsSingleton() {}, + AboutNewTab: {}, + Glean: { + newtab: { + opened: { + record() {}, + }, + closed: { + record() {}, + }, + locale: { + set() {}, + }, + newtabCategory: { + set() {}, + }, + homepageCategory: { + set() {}, + }, + blockedSponsors: { + set() {}, + }, + sovAllocation: { + set() {}, + }, + }, + newtabSearch: { + enabled: { + set() {}, + }, + }, + pocket: { + enabled: { + set() {}, + }, + impression: { + record() {}, + }, + isSignedIn: { + set() {}, + }, + sponsoredStoriesEnabled: { + set() {}, + }, + click: { + record() {}, + }, + save: { + record() {}, + }, + topicClick: { + record() {}, + }, + }, + topsites: { + enabled: { + set() {}, + }, + sponsoredEnabled: { + set() {}, + }, + impression: { + record() {}, + }, + click: { + record() {}, + }, + rows: { + set() {}, + }, + showPrivacyClick: { + record() {}, + }, + dismiss: { + record() {}, + }, + prefChanged: { + record() {}, + }, + }, + topSites: { + pingType: { + set() {}, + }, + position: { + set() {}, + }, + source: { + set() {}, + }, + tileId: { + set() {}, + }, + reportingUrl: { + set() {}, + }, + advertiser: { + set() {}, + }, + contextId: { + set() {}, + }, + }, + }, + GleanPings: { + newtab: { + submit() {}, + }, + topSites: { + submit() {}, + }, + }, + Utils: { + SERVER_URL: "bogus://foo", + }, +}; +overrider.set(TEST_GLOBAL); + +describe("activity-stream", () => { + after(() => overrider.restore()); + files.forEach(file => req(file)); +}); diff --git a/browser/components/newtab/karma.mc.config.js b/browser/components/newtab/karma.mc.config.js index 3a8c0cd311d4..44f0657bfa36 100644 --- a/browser/components/newtab/karma.mc.config.js +++ b/browser/components/newtab/karma.mc.config.js @@ -206,46 +206,12 @@ module.exports = function (config) { functions: 0, branches: 0, }, - "content-src/lib/aboutwelcome-utils.js": { - statements: 50, - lines: 50, - functions: 50, - branches: 0, - }, "content-src/lib/link-menu-options.js": { statements: 96, lines: 96, functions: 96, branches: 70, }, - "content-src/aboutwelcome/components/LanguageSwitcher.jsx": { - // This file is covered by the mochitest: browser_aboutwelcome_multistage_languageSwitcher.js - statements: 0, - lines: 0, - functions: 0, - branches: 0, - }, - "content-src/aboutwelcome/components/EmbeddedMigrationWizard.jsx": { - // This file is covered by the mochitest: browser_aboutwelcome_multistage_mr.js - // Can't be unit tested because it relies on the migration-wizard custom element - statements: 0, - lines: 0, - functions: 0, - branches: 0, - }, - "content-src/aboutwelcome/components/AddonsPicker.jsx": { - // This file is covered by the mochitest: browser_aboutwelcome_multistage_addonspicker.js - statements: 0, - lines: 0, - functions: 0, - branches: 0, - }, - "content-src/aboutwelcome/**/*.jsx": { - statements: 62, - lines: 60, - functions: 50, - branches: 50, - }, "content-src/components/**/*.jsx": { statements: 51.1, lines: 52.38,