Add WidgetManager tests
parent
bdb2bb294d
commit
f23418020a
|
@ -17,7 +17,7 @@
|
|||
"package:chrome": "npm run build:app && web-ext build -s ./dist/webext/ -i app/manifest.json -i app/index.html -i manifest.firefox.json -n chrome.zip",
|
||||
"package:firefox": "npm run build:app && cp src/webext/manifest.firefox.json dist/webext/manifest.json && web-ext build -s ./dist/webext/ -i app/manifest.json -i manifest.firefox.json -i app/index.html -n firefox.zip",
|
||||
"lint": "eslint 'src/**/*.{js,ts,tsx}' --fix",
|
||||
"test": "NODE_PATH=src mocha -r ts-node/register tests/**/*.test.ts",
|
||||
"test": "TS_NODE_FILES=1 NODE_PATH=src mocha -r ts-node/register tests/**/*.test.ts",
|
||||
"coverage": "nyc -r lcov -e .ts -x \"*.test.ts\" npm run test",
|
||||
"trans:extract": "formatjs extract 'src/app/**/*.ts*' --out-file src/app/locale/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format utils/translation-format.js && node utils/update_translations.js",
|
||||
"trans:compile": "node utils/compile_translations.js"
|
||||
|
|
|
@ -119,7 +119,7 @@ class DelegateStorage implements IStorage {
|
|||
}
|
||||
|
||||
|
||||
if (typeof browser === 'undefined' &&
|
||||
if (typeof browser === 'undefined' && typeof navigator !== "undefined" &&
|
||||
navigator.storage && navigator.storage.persist) {
|
||||
navigator.storage.persist()
|
||||
.then((isPersisted) =>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { storage } from "./Storage";
|
||||
import { IStorage } from "./Storage";
|
||||
import { Vector2 } from "./utils/Vector2";
|
||||
import { WidgetTypes } from "./widgets";
|
||||
import { getInitialTheme, Widget } from "./Widget";
|
||||
|
@ -13,10 +13,10 @@ export class WidgetManager {
|
|||
|
||||
widgets: (Widget<any>)[] = [];
|
||||
|
||||
constructor() {}
|
||||
constructor(private storage: IStorage) {}
|
||||
|
||||
async load() {
|
||||
const json = await storage.get<Widget<any>[]>("widgets");
|
||||
const json = await this.storage.get<Widget<any>[]>("widgets");
|
||||
if (!json) {
|
||||
this.resetToDefault();
|
||||
return;
|
||||
|
@ -43,7 +43,7 @@ export class WidgetManager {
|
|||
}
|
||||
|
||||
save() {
|
||||
storage.set("widgets", this.widgets);
|
||||
this.storage.set("widgets", this.widgets);
|
||||
}
|
||||
|
||||
resetToDefault() {
|
||||
|
@ -52,11 +52,11 @@ export class WidgetManager {
|
|||
"HelpAbout", "Weather", "Feed", "Notes"].forEach(this.createWidget.bind(this));
|
||||
}
|
||||
|
||||
createWidget(type: string) {
|
||||
createWidget<T>(type: string): Widget<T> {
|
||||
this.id_counter++;
|
||||
|
||||
const widget_type = WidgetTypes[type];
|
||||
const widget = {
|
||||
const widget: Widget<T> = {
|
||||
id: this.id_counter,
|
||||
type: type,
|
||||
position: undefined,
|
||||
|
@ -71,6 +71,8 @@ export class WidgetManager {
|
|||
}
|
||||
|
||||
this.save();
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
removeWidget(id: number) {
|
||||
|
|
|
@ -10,9 +10,10 @@ import { FormattedMessage, IntlProvider } from "react-intl";
|
|||
import { getTranslation, getUserLocale } from "app/locale";
|
||||
import { applyTheme, ThemeConfig } from "./settings/ThemeSettings";
|
||||
import ReviewRequester from "./ReviewRequester";
|
||||
import { storage } from "app/Storage";
|
||||
|
||||
|
||||
const widgetManager = new WidgetManager();
|
||||
const widgetManager = new WidgetManager(storage);
|
||||
|
||||
export default function App() {
|
||||
const [loadingRes,] = usePromise(async () => {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
interface Config {
|
||||
API_URL: string;
|
||||
PROXY_URL: string;
|
||||
}
|
||||
|
||||
declare var config: Config;
|
||||
declare const app_version: string;
|
|
@ -3,14 +3,13 @@ import { miscMessages } from "app/locale/common";
|
|||
import { IntlShape, useIntl } from "react-intl";
|
||||
import { usePromise } from "./promises";
|
||||
|
||||
const proxy_url = config.PROXY_URL;
|
||||
|
||||
function makeProxy(url: string) {
|
||||
if (typeof browser !== 'undefined') {
|
||||
console.log("Detected running as webext");
|
||||
return url;
|
||||
} else {
|
||||
const ret = new URL(proxy_url);
|
||||
const ret = new URL(config.PROXY_URL);
|
||||
ret.searchParams.set("url", url);
|
||||
return ret.toString();
|
||||
}
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
interface Config {
|
||||
API_URL: string;
|
||||
PROXY_URL: string;
|
||||
PROXY_ALLOWED_HOSTS: string[];
|
||||
}
|
||||
|
||||
declare global {
|
||||
const config: Config;
|
||||
const app_version: string;
|
||||
}
|
||||
|
||||
import React from "react";
|
||||
import { render } from "react-dom";
|
||||
import App from "./components/App";
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import { IStorage } from "app/Storage";
|
||||
|
||||
export default class DummyStorage implements IStorage {
|
||||
private values: { [key: string]: any } = {};
|
||||
|
||||
async getAll(): Promise<{ [key: string]: any; }> {
|
||||
return { ...this.values };
|
||||
}
|
||||
|
||||
async get<T>(key: string): Promise<T | null> {
|
||||
return this.values[key] ?? null;
|
||||
}
|
||||
|
||||
async set<T>(key: string, value: T): Promise<void> {
|
||||
this.values[key] = value;
|
||||
}
|
||||
|
||||
async remove(key: string): Promise<void> {
|
||||
delete this.values[key];
|
||||
}
|
||||
|
||||
async clear(): Promise<void> {
|
||||
this.values = {}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,10 @@ describe("WidgetLayouter", function() {
|
|||
type: "Type",
|
||||
position: V(1, 1),
|
||||
size: V(3, 3),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
layouter.resolveAll([widget]);
|
||||
|
@ -52,21 +55,30 @@ describe("WidgetLayouter", function() {
|
|||
id: 1,
|
||||
type: "Type",
|
||||
size: V(3, 3),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
const widget2 : Widget<any> = {
|
||||
id: 1,
|
||||
type: "Type",
|
||||
size: V(15, 2),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
const widget3 : Widget<any> = {
|
||||
id: 1,
|
||||
type: "Type",
|
||||
size: V(3, 3),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
layouter.resolveAll([widget1, widget2, widget3]);
|
||||
|
@ -86,7 +98,10 @@ describe("WidgetLayouter", function() {
|
|||
id: 1,
|
||||
type: "Type",
|
||||
size: V(3, 3),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
const widget2 : Widget<any> = {
|
||||
|
@ -94,7 +109,10 @@ describe("WidgetLayouter", function() {
|
|||
type: "Type",
|
||||
position: V(0, 0),
|
||||
size: V(15, 2),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
const widget3 : Widget<any> = {
|
||||
|
@ -102,7 +120,10 @@ describe("WidgetLayouter", function() {
|
|||
type: "Type",
|
||||
position: V(3, 0),
|
||||
size: V(3, 3),
|
||||
props: {}
|
||||
props: {},
|
||||
theme: {
|
||||
showPanelBG: false
|
||||
}
|
||||
};
|
||||
|
||||
layouter.resolveAll([widget1, widget2, widget3]);
|
|
@ -0,0 +1,123 @@
|
|||
import { LinkBoxProps } from "app/components/LinkBox";
|
||||
import { Vector2 } from "app/utils/Vector2";
|
||||
import { WidgetManager } from "app/WidgetManager";
|
||||
import { expect } from "chai";
|
||||
import DummyStorage from "./DummyStorage";
|
||||
|
||||
describe("WidgetManager::create", () => {
|
||||
it("createsDefaultWidgets", async () => {
|
||||
const storage = new DummyStorage();
|
||||
const wm = new WidgetManager(storage);
|
||||
await wm.load();
|
||||
expect(wm.widgets.length).to.equal(9);
|
||||
});
|
||||
|
||||
it("copiesProps", async () => {
|
||||
const storage = new DummyStorage();
|
||||
storage.set("widgets", [
|
||||
{
|
||||
id: "123",
|
||||
type: "Notes",
|
||||
props: {},
|
||||
size: new Vector2(3, 5),
|
||||
},
|
||||
]);
|
||||
|
||||
const wm = new WidgetManager(storage);
|
||||
expect(wm.widgets.length).to.equal(0);
|
||||
await wm.load();
|
||||
expect(wm.widgets.length).to.equal(1);
|
||||
|
||||
const widget1 = wm.createWidget<LinkBoxProps>("Links");
|
||||
const widget2 = wm.createWidget<LinkBoxProps>("Links");
|
||||
expect(widget1.props.links.length).to.equal(6);
|
||||
expect(widget2.props.links.length).to.equal(6);
|
||||
|
||||
widget1.props.links.push({
|
||||
id: "123",
|
||||
title: "Title",
|
||||
url: "url",
|
||||
});
|
||||
|
||||
expect(widget1.props.links.length).to.equal(7);
|
||||
expect(widget2.props.links.length).to.equal(6);
|
||||
});
|
||||
|
||||
it("copiesTheme", async () => {
|
||||
const storage = new DummyStorage();
|
||||
storage.set("widgets", []);
|
||||
const wm = new WidgetManager(storage);
|
||||
await wm.load();
|
||||
expect(wm.widgets.length).to.equal(0);
|
||||
|
||||
const widget1 = wm.createWidget<LinkBoxProps>("Links");
|
||||
const widget2 = wm.createWidget<LinkBoxProps>("Links");
|
||||
expect(widget1.theme.useIconBar).is.false;
|
||||
widget1.theme.useIconBar = true;
|
||||
expect(widget1.theme.useIconBar).is.true;
|
||||
expect(widget2.theme.useIconBar).is.false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("WidgetManager::load", () => {
|
||||
it("adds theme", async () => {
|
||||
const storage = new DummyStorage();
|
||||
storage.set("widgets", [
|
||||
{
|
||||
id: "123",
|
||||
type: "Notes",
|
||||
props: {},
|
||||
size: new Vector2(3, 5),
|
||||
},
|
||||
{
|
||||
id: "124",
|
||||
type: "Clock",
|
||||
props: {},
|
||||
size: new Vector2(3, 5),
|
||||
},
|
||||
]);
|
||||
|
||||
const wm = new WidgetManager(storage);
|
||||
expect(wm.widgets.length).to.equal(0);
|
||||
await wm.load();
|
||||
expect(wm.widgets.length).to.equal(2);
|
||||
|
||||
{
|
||||
const notesWidget = wm.widgets[0];
|
||||
expect(notesWidget.theme).not.null;
|
||||
expect(notesWidget.theme.showPanelBG).to.be.true;
|
||||
}
|
||||
|
||||
{
|
||||
const clockWidget = wm.widgets[1];
|
||||
expect(clockWidget.theme).not.null;
|
||||
expect(clockWidget.theme.showPanelBG).to.be.false;
|
||||
}
|
||||
});
|
||||
|
||||
it("runs load hook", async () => {
|
||||
const storage = new DummyStorage();
|
||||
storage.set("widgets", [
|
||||
{
|
||||
id: "123",
|
||||
type: "TopSites",
|
||||
props: {
|
||||
useIconBar: false,
|
||||
},
|
||||
size: new Vector2(3, 5),
|
||||
},
|
||||
]);
|
||||
|
||||
const wm = new WidgetManager(storage);
|
||||
expect(wm.widgets.length).to.equal(0);
|
||||
await wm.load();
|
||||
expect(wm.widgets.length).to.equal(1);
|
||||
|
||||
const widget = wm.widgets[0];
|
||||
expect(widget.props).not.to.haveOwnProperty("useIconBar");
|
||||
expect(widget.theme).not.null;
|
||||
expect(widget.theme.showPanelBG).to.be.true;
|
||||
expect(widget.theme.useIconBar).to.be.false;
|
||||
});
|
||||
});
|
|
@ -4,6 +4,7 @@
|
|||
"module": "ES2015"
|
||||
},
|
||||
"exclude": [
|
||||
"src/server"
|
||||
"src/server",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
"sourceMap": true,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/web-ext-types"
|
||||
"./node_modules/web-ext-types",
|
||||
"src/app/custom.d.ts"
|
||||
],
|
||||
"baseUrl": "src",
|
||||
"esModuleInterop": true,
|
||||
|
@ -15,6 +16,6 @@
|
|||
"resolveJsonModule": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
"src", "tests"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
"extends": "./tsconfig.json",
|
||||
"exclude": [
|
||||
"src/app",
|
||||
"src/webext"
|
||||
"src/webext",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue