forked from mirrors/gecko-dev
Bug 1866802 - Move ASRouterAdmin test to browser/components/asrouter. r=pdahiya
Differential Revision: https://phabricator.services.mozilla.com/D194812
This commit is contained in:
parent
4b9f3545e2
commit
a7ac21fdb8
7 changed files with 6197 additions and 97 deletions
|
|
@ -19,32 +19,27 @@ module.exports = {
|
|||
overrides: [
|
||||
{
|
||||
// Only mark the files as modules which are actually modules.
|
||||
// TODO: Add "tests/unit/**" to this list once we get our tests built.
|
||||
files: ["content-src/**"],
|
||||
files: ["content-src/**", "tests/unit/**"],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
{
|
||||
// TODO: Add ./*.js and tests/unit/** to this list if necessary
|
||||
files: ["./*.js", "content-src/**"],
|
||||
files: ["./*.js", "content-src/**", "tests/unit/**"],
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
},
|
||||
/* TODO: Turn this rule on when I move the tests over.
|
||||
{
|
||||
// Use a configuration that's appropriate for modules, workers and
|
||||
// non-production files.
|
||||
files: ["modules/*.jsm", "tests/**"],
|
||||
rules: {
|
||||
"no-implicit-globals": "off",
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
// TODO: Add "tests/unit/**" to this list once we get our tests built.
|
||||
files: ["content-src/**"],
|
||||
// Use a configuration that's appropriate for modules, workers and
|
||||
// non-production files.
|
||||
files: ["tests/**"],
|
||||
rules: {
|
||||
"no-implicit-globals": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["content-src/**", "tests/unit/**"],
|
||||
rules: {
|
||||
// Disallow commonjs in these directories.
|
||||
"import/no-commonjs": 2,
|
||||
|
|
@ -52,28 +47,27 @@ module.exports = {
|
|||
"react/jsx-no-bind": 0,
|
||||
},
|
||||
},
|
||||
/* TODO: Turn this rule on when I move the tests over.
|
||||
{
|
||||
// These tests simulate the browser environment.
|
||||
files: "tests/unit/**",
|
||||
env: {
|
||||
browser: true,
|
||||
mocha: true,
|
||||
},
|
||||
globals: {
|
||||
assert: true,
|
||||
chai: true,
|
||||
sinon: true,
|
||||
},
|
||||
{
|
||||
// These tests simulate the browser environment.
|
||||
files: "tests/unit/**",
|
||||
env: {
|
||||
browser: true,
|
||||
mocha: true,
|
||||
},
|
||||
{
|
||||
files: "tests/**",
|
||||
rules: {
|
||||
"func-name-matching": 0,
|
||||
"lines-between-class-members": 0,
|
||||
"require-await": 0,
|
||||
},
|
||||
},*/
|
||||
globals: {
|
||||
assert: true,
|
||||
chai: true,
|
||||
sinon: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: "tests/**",
|
||||
rules: {
|
||||
"func-name-matching": 0,
|
||||
"lines-between-class-members": 0,
|
||||
"require-await": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
"fetch-options/no-fetch-credentials": "error",
|
||||
|
|
|
|||
203
browser/components/asrouter/karma.mc.config.js
Normal file
203
browser/components/asrouter/karma.mc.config.js
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/* 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: {
|
||||
"content-src/components/ASRouterAdmin/*.jsx": {
|
||||
statements: 0,
|
||||
lines: 0,
|
||||
functions: 0,
|
||||
branches: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
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 },
|
||||
});
|
||||
};
|
||||
5022
browser/components/asrouter/package-lock.json
generated
5022
browser/components/asrouter/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -12,13 +12,32 @@
|
|||
"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",
|
||||
"mocha": "9.1.3",
|
||||
"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"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,262 @@
|
|||
import { ASRouterAdminInner } from "content-src/components/ASRouterAdmin/ASRouterAdmin";
|
||||
import { ASRouterUtils } from "content-src/asrouter/asrouter-utils";
|
||||
import { GlobalOverrider } from "test/unit/utils";
|
||||
import React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
|
||||
describe("ASRouterAdmin", () => {
|
||||
let globalOverrider;
|
||||
let sandbox;
|
||||
let wrapper;
|
||||
let globals;
|
||||
let FAKE_PROVIDER_PREF = [
|
||||
{
|
||||
enabled: true,
|
||||
id: "local_testing",
|
||||
localProvider: "TestProvider",
|
||||
type: "local",
|
||||
},
|
||||
];
|
||||
let FAKE_PROVIDER = [
|
||||
{
|
||||
enabled: true,
|
||||
id: "local_testing",
|
||||
localProvider: "TestProvider",
|
||||
messages: [],
|
||||
type: "local",
|
||||
},
|
||||
];
|
||||
beforeEach(() => {
|
||||
globalOverrider = new GlobalOverrider();
|
||||
sandbox = sinon.createSandbox();
|
||||
sandbox.stub(ASRouterUtils, "getPreviewEndpoint").returns("foo");
|
||||
globals = {
|
||||
ASRouterMessage: sandbox.stub().resolves(),
|
||||
ASRouterAddParentListener: sandbox.stub(),
|
||||
ASRouterRemoveParentListener: sandbox.stub(),
|
||||
};
|
||||
globalOverrider.set(globals);
|
||||
wrapper = shallow(<ASRouterAdminInner location={{ routes: [""] }} />);
|
||||
wrapper.setState({ devtoolsEnabled: true });
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
globalOverrider.restore();
|
||||
});
|
||||
it("should render ASRouterAdmin component", () => {
|
||||
assert.ok(wrapper.exists());
|
||||
});
|
||||
it("should send ADMIN_CONNECT_STATE on mount", () => {
|
||||
assert.calledOnce(globals.ASRouterMessage);
|
||||
assert.calledWith(globals.ASRouterMessage, {
|
||||
type: "ADMIN_CONNECT_STATE",
|
||||
data: { endpoint: "foo" },
|
||||
});
|
||||
});
|
||||
describe("#getSection", () => {
|
||||
it("should render a message provider section by default", () => {
|
||||
assert.equal(wrapper.find("h2").at(1).text(), "Messages");
|
||||
});
|
||||
it("should render a targeting section for targeting route", () => {
|
||||
wrapper = shallow(
|
||||
<ASRouterAdminInner location={{ routes: ["targeting"] }} />
|
||||
);
|
||||
wrapper.setState({ devtoolsEnabled: true });
|
||||
assert.equal(wrapper.find("h2").at(0).text(), "Targeting Utilities");
|
||||
});
|
||||
it("should render two error messages", () => {
|
||||
wrapper = shallow(
|
||||
<ASRouterAdminInner location={{ routes: ["errors"] }} Sections={[]} />
|
||||
);
|
||||
wrapper.setState({ devtoolsEnabled: true });
|
||||
const firstError = {
|
||||
timestamp: Date.now() + 100,
|
||||
error: { message: "first" },
|
||||
};
|
||||
const secondError = {
|
||||
timestamp: Date.now(),
|
||||
error: { message: "second" },
|
||||
};
|
||||
wrapper.setState({
|
||||
providers: [{ id: "foo", errors: [firstError, secondError] }],
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
wrapper.find("tbody tr").at(0).find("td").at(0).text(),
|
||||
"foo"
|
||||
);
|
||||
assert.lengthOf(wrapper.find("tbody tr"), 2);
|
||||
assert.equal(
|
||||
wrapper.find("tbody tr").at(0).find("td").at(1).text(),
|
||||
secondError.error.message
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("#render", () => {
|
||||
beforeEach(() => {
|
||||
wrapper.setState({
|
||||
providerPrefs: [],
|
||||
providers: [],
|
||||
userPrefs: {},
|
||||
});
|
||||
});
|
||||
describe("#renderProviders", () => {
|
||||
it("should render the provider", () => {
|
||||
wrapper.setState({
|
||||
providerPrefs: FAKE_PROVIDER_PREF,
|
||||
providers: FAKE_PROVIDER,
|
||||
});
|
||||
|
||||
// Header + 1 item
|
||||
assert.lengthOf(wrapper.find(".message-item"), 2);
|
||||
});
|
||||
});
|
||||
describe("#renderMessages", () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(ASRouterUtils, "blockById").resolves();
|
||||
sandbox.stub(ASRouterUtils, "unblockById").resolves();
|
||||
sandbox.stub(ASRouterUtils, "overrideMessage").resolves({ foo: "bar" });
|
||||
sandbox.stub(ASRouterUtils, "sendMessage").resolves();
|
||||
wrapper.setState({
|
||||
messageFilter: "all",
|
||||
messageBlockList: [],
|
||||
messageImpressions: { foo: 2 },
|
||||
groups: [{ id: "messageProvider", enabled: true }],
|
||||
providers: [{ id: "messageProvider", enabled: true }],
|
||||
});
|
||||
});
|
||||
it("should render a message when no filtering is applied", () => {
|
||||
wrapper.setState({
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
provider: "messageProvider",
|
||||
groups: ["messageProvider"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.lengthOf(wrapper.find(".message-id"), 1);
|
||||
wrapper.find(".message-item button.primary").simulate("click");
|
||||
assert.calledOnce(ASRouterUtils.blockById);
|
||||
assert.calledWith(ASRouterUtils.blockById, "foo");
|
||||
});
|
||||
it("should render a blocked message", () => {
|
||||
wrapper.setState({
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
groups: ["messageProvider"],
|
||||
provider: "messageProvider",
|
||||
},
|
||||
],
|
||||
messageBlockList: ["foo"],
|
||||
});
|
||||
assert.lengthOf(wrapper.find(".message-item.blocked"), 1);
|
||||
wrapper.find(".message-item.blocked button").simulate("click");
|
||||
assert.calledOnce(ASRouterUtils.unblockById);
|
||||
assert.calledWith(ASRouterUtils.unblockById, "foo");
|
||||
});
|
||||
it("should render a message if provider matches filter", () => {
|
||||
wrapper.setState({
|
||||
messageFilter: "messageProvider",
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
provider: "messageProvider",
|
||||
groups: ["messageProvider"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.lengthOf(wrapper.find(".message-id"), 1);
|
||||
});
|
||||
it("should override with the selected message", async () => {
|
||||
wrapper.setState({
|
||||
messageFilter: "messageProvider",
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
provider: "messageProvider",
|
||||
groups: ["messageProvider"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.lengthOf(wrapper.find(".message-id"), 1);
|
||||
wrapper.find(".message-item button.show").simulate("click");
|
||||
assert.calledOnce(ASRouterUtils.overrideMessage);
|
||||
assert.calledWith(ASRouterUtils.overrideMessage, "foo");
|
||||
await ASRouterUtils.overrideMessage();
|
||||
assert.equal(wrapper.state().foo, "bar");
|
||||
});
|
||||
it("should hide message if provider filter changes", () => {
|
||||
wrapper.setState({
|
||||
messageFilter: "messageProvider",
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
provider: "messageProvider",
|
||||
groups: ["messageProvider"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.lengthOf(wrapper.find(".message-id"), 1);
|
||||
|
||||
wrapper.find("select").simulate("change", { target: { value: "bar" } });
|
||||
|
||||
assert.lengthOf(wrapper.find(".message-id"), 0);
|
||||
});
|
||||
it("should not display Reset All button if provider filter value is set to all or test providers", () => {
|
||||
wrapper.setState({
|
||||
messageFilter: "messageProvider",
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
provider: "messageProvider",
|
||||
groups: ["messageProvider"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.lengthOf(wrapper.find(".messages-reset"), 1);
|
||||
wrapper.find("select").simulate("change", { target: { value: "all" } });
|
||||
|
||||
assert.lengthOf(wrapper.find(".messages-reset"), 0);
|
||||
|
||||
wrapper
|
||||
.find("select")
|
||||
.simulate("change", { target: { value: "test_local_testing" } });
|
||||
assert.lengthOf(wrapper.find(".messages-reset"), 0);
|
||||
});
|
||||
it("should trigger disable and enable provider on Reset All button click", () => {
|
||||
wrapper.setState({
|
||||
messageFilter: "messageProvider",
|
||||
messages: [
|
||||
{
|
||||
id: "foo",
|
||||
provider: "messageProvider",
|
||||
groups: ["messageProvider"],
|
||||
},
|
||||
],
|
||||
providerPrefs: [
|
||||
{
|
||||
id: "messageProvider",
|
||||
},
|
||||
],
|
||||
});
|
||||
wrapper.find(".messages-reset").simulate("click");
|
||||
assert.calledTwice(ASRouterUtils.sendMessage);
|
||||
assert.calledWith(ASRouterUtils.sendMessage, {
|
||||
type: "DISABLE_PROVIDER",
|
||||
data: "messageProvider",
|
||||
});
|
||||
assert.calledWith(ASRouterUtils.sendMessage, {
|
||||
type: "ENABLE_PROVIDER",
|
||||
data: "messageProvider",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
720
browser/components/asrouter/tests/unit/unit-entry.js
Normal file
720
browser/components/asrouter/tests/unit/unit-entry.js
Normal file
|
|
@ -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("asrouter", () => {
|
||||
after(() => overrider.restore());
|
||||
files.forEach(file => req(file));
|
||||
});
|
||||
Loading…
Reference in a new issue