test utils refactoring

This commit is contained in:
Géry Debongnie
2019-03-04 22:47:20 +01:00
parent 8926b8828f
commit a162e40fe0
15 changed files with 494 additions and 394 deletions
+3
View File
@@ -232,6 +232,9 @@ export class QWeb {
const parser = new DOMParser();
const doc = parser.parseFromString(xmlstr, "text/xml");
const templates = doc.getElementsByTagName("templates")[0];
if (!templates) {
return;
}
for (let elem of <any>templates.children) {
const name = elem.getAttribute("t-name");
this._processTemplate(elem);
+14 -4
View File
@@ -1,9 +1,14 @@
//------------------------------------------------------------------------------
// Registry code
//------------------------------------------------------------------------------
/**
* The registry is basically a simple hashmap. It is only a little safer and
* more structured than a simple object.
*/
export class Registry<T> {
private map: { [key: string]: T } = {};
/**
* Add an element to the registry. Note that the add method returns the
* registry, to it can be chained.
*/
add(key: string, item: T): Registry<T> {
if (key in this.map) {
throw new Error(`Key ${key} already exists!`);
@@ -12,7 +17,12 @@ export class Registry<T> {
return this;
}
get(key: string): T {
/**
* Returns the element corresponding to the key
*
* Nothing is done to check that the key actually exists.
*/
get(key: string): T | undefined {
return this.map[key];
}
}
+29 -17
View File
@@ -83,22 +83,24 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
default:
throw new Error("unhandled action");
}
const action: Action = {
id: this.generateID(),
executor,
activate() {
if (self.currentAction && self.currentAction.widget) {
self.currentAction.widget.destroy();
if (executor) {
const action: Action = {
id: this.generateID(),
executor,
activate() {
if (self.currentAction && self.currentAction.widget) {
self.currentAction.widget.destroy();
}
self.currentAction = action;
self.update({
inHome: false
});
document.title = descr.name + " - Odoo";
}
self.currentAction = action;
self.update({
inHome: false
});
document.title = descr.name + " - Odoo";
}
};
self.lastAction = action;
this.trigger("update_action", action);
};
self.lastAction = action;
this.trigger("update_action", action);
}
}
doActWindowAction(descr: ActWindowActionDescription) {
@@ -111,11 +113,21 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
};
}
doClientAction(descr: ClientActionDescription) {
doClientAction(
descr: ClientActionDescription
): Action["executor"] | undefined {
let key = descr.tag;
let Widget = this.actionRegistry.get(key);
if (!Widget) {
this.addNotification({
title: "Invalid Client Action",
type: "warning",
message: `Cannot find widget '${key}' in the action registry`
});
return;
}
return async function executor(this: Action, parent: Widget<any, any>) {
const widget = new Widget(parent, {});
const widget = new Widget!(parent, {});
const div = document.createElement("div");
await widget.mount(div);
this.widget = widget;
+11 -104
View File
@@ -1,104 +1,11 @@
import { readFile } from "fs";
import { WEnv } from "../../src/ts/core/component";
import { Callback } from "../../src/ts/core/event_bus";
import { QWeb } from "../../src/ts/core/qweb_vdom";
import { idGenerator } from "../../src/ts/core/utils";
import { getMenuInfo } from "../../src/ts/loaders";
import { menuInfo, actions } from "./test_data";
import { actionRegistry } from "../../src/ts/registries";
import { IRouter, Query, RouterEvent } from "../../src/ts/services/router";
import { MenuInfo, Services, Store } from "../../src/ts/store/store";
export function makeTestFixture() {
let fixture = document.createElement("div");
document.body.appendChild(fixture);
return fixture;
}
export function makeTestWEnv(): WEnv {
return {
qweb: new QWeb(),
getID: idGenerator()
};
}
export function makeTestStore(services: Partial<Services> = {}): Store {
const fullservices: Services = Object.assign(
{
rpc: mockFetch,
router: new MockRouter()
},
services
);
const menuInfo = makeDemoMenuInfo();
const store = new Store(fullservices, menuInfo, actionRegistry);
return store;
}
export function mockFetch(route: string, params: any): Promise<any> {
if (route === "web/action/load") {
const action = actions.find(a => a.id === params.action_id);
return Promise.resolve(action);
}
return Promise.resolve(true);
}
export class MockRouter implements IRouter {
currentQuery: Query;
constructor(query: Query = {}) {
this.currentQuery = query;
}
navigate(query: Query) {
this.currentQuery = query;
}
on(event: RouterEvent, owner: any, callback: Callback) {}
getQuery(): Query {
return this.currentQuery;
}
formatURL(path: string, query: Query): string {
return "";
}
}
export function normalize(str: string): string {
return str.replace(/\s+/g, "");
}
export async function loadTemplates(): Promise<string> {
return new Promise((resolve, reject) => {
readFile("web/static/src/xml/templates.xml", "utf-8", (err, result) => {
resolve(result);
});
});
}
export function makeDemoMenuInfo(): MenuInfo {
return getMenuInfo(menuInfo);
}
export function nextMicroTick(): Promise<void> {
return Promise.resolve();
}
export function nextTick(): Promise<void> {
return new Promise(resolve => setTimeout(resolve));
}
interface Deferred extends Promise<any> {
resolve(val?: any): void;
reject(): void;
}
export function makeDeferred(): Deferred {
let resolve, reject;
let def = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
(<Deferred>def).resolve = resolve;
(<Deferred>def).reject = reject;
return <Deferred>def;
}
export { MockRouter } from "./mock_router";
export { MockServer } from "./mock_server";
export { TestData, makeTestData, makeMenuInfo } from "./test_data";
export { TestEnv, TestInfo, makeTestWEnv, makeTestEnv } from "./test_env";
export {
nextMicroTick,
nextTick,
makeTestFixture,
normalize,
makeDeferred
} from "./test_utils";
+22
View File
@@ -0,0 +1,22 @@
import { Callback } from "../../src/ts/core/event_bus";
import { IRouter, Query, RouterEvent } from "../../src/ts/services/router";
export class MockRouter implements IRouter {
currentQuery: Query;
constructor(query: Query = {}) {
this.currentQuery = query;
}
navigate(query: Query) {
this.currentQuery = query;
}
on(event: RouterEvent, owner: any, callback: Callback) {}
getQuery(): Query {
return this.currentQuery;
}
formatURL(path: string, query: Query): string {
return "";
}
}
+17
View File
@@ -0,0 +1,17 @@
import { TestData } from "./test_data";
export class MockServer {
data: TestData;
constructor(data: TestData) {
this.data = data;
}
rpc(route: string, params: any): Promise<any> {
if (route === "web/action/load") {
const action = this.data.actions.find(a => a.id === params.action_id);
return Promise.resolve(action);
}
return Promise.resolve(true);
}
}
+216 -175
View File
@@ -1,179 +1,220 @@
import { BaseMenuItem } from "../../src/ts/loaders";
import { readFile } from "fs";
import { BaseMenuItem, getMenuInfo } from "../../src/ts/loaders";
import { actionRegistry } from "../../src/ts/registries";
import { ActionDescription } from "../../src/ts/store/action_manager_mixin";
import { MenuInfo } from "../../src/ts/store/store";
import { Registry } from "../../src/ts/core/registry";
export const menuInfo: BaseMenuItem[] = [
{
id: 96,
name: "Discuss",
parent_id: false,
action: "ir.actions.client,131",
icon: "fa fa-comment",
children: []
},
{
id: 205,
name: "Notes",
parent_id: false,
action: "ir.actions.act_window,250",
icon: "fa fa-pen",
children: []
},
{
id: 409,
name: "CRM",
parent_id: false,
action: "ir.actions.act_window,597",
icon: "fa fa-handshake",
children: [
{
id: 418,
name: "Sales",
parent_id: 409,
action: false,
icon: false,
children: [
{
id: 423,
name: "My Pipeline",
parent_id: 418,
action: "ir.actions.act_window,597",
icon: false,
children: []
},
{
id: 812,
name: "My Quotations",
parent_id: 418,
action: "ir.actions.act_window,1051",
icon: false,
children: []
},
{
id: 419,
name: "Team Pipelines",
parent_id: 418,
action: "ir.actions.act_window,275",
icon: false,
children: []
}
]
},
{
id: 421,
name: "Leads",
parent_id: 409,
action: false,
icon: false,
children: [
{
id: 422,
name: "Leads",
parent_id: 421,
action: "ir.actions.act_window,595",
icon: false,
children: []
},
{
id: 752,
name: "Scoring Rules",
parent_id: 421,
icon: false,
action: "ir.actions.act_window,1083",
children: []
}
]
}
]
}
];
export interface TestData {
menuInfo: MenuInfo;
actions: ActionDescription[];
actionRegistry: typeof actionRegistry;
templates: string;
}
export const actions: ActionDescription[] = [
{
id: 131,
type: "ir.actions.client",
target: "current",
name: "Discuss",
tag: "mail.discuss"
},
{
id: 250,
type: "ir.actions.act_window",
name: "Notes",
target: "current",
domain: false,
context: "{}",
views: [[false, "kanban"], [false, "list"], [false, "form"]],
res_id: 0,
res_model: "note.note"
},
{
id: 597,
type: "ir.actions.act_window",
name: "Pipeline",
target: "current",
domain: false,
context: { default_team_id: 1 },
views: [[2103, "kanban"], [2106, "list"], [2105, "form"]],
res_id: 0,
res_model: "crm.lead"
},
{
id: 1051,
type: "ir.actions.act_window",
name: "Quotations",
target: "current",
domain: false,
context: "{'search_default_my_quotation': 1}",
views: [
[3387, "list"],
[3385, "kanban"],
[3389, "form"],
[3382, "calendar"],
[3384, "pivot"],
[3383, "graph"]
],
res_id: 0,
res_model: "sale.order"
},
{
id: 275,
type: "ir.actions.act_window",
name: "Team Pipelines",
target: "current",
context: "{}",
domain: "[('use_opportunities', '=', True)]",
views: [[false, "kanban"], [false, "form"]],
res_id: 0,
res_model: "crm.team"
},
{
id: 595,
type: "ir.actions.act_window",
name: "Leads",
target: "current",
context:
"{ 'default_type':'lead', 'search_default_type': 'lead', 'search_default_to_process':1, }",
domain: "['|', ('type','=','lead'), ('type','=',False)]",
views: [
[2098, "list"],
[2099, "kanban"],
[2100, "calendar"],
[2108, "pivot"],
[2107, "graph"],
[false, "form"]
],
res_id: 0,
res_model: "crm.lead"
},
{
id: 1083,
type: "ir.actions.act_window",
name: "Scores",
target: "current",
context: "{}",
domain: false,
views: [[false, "list"], [false, "kanban"], [false, "form"]],
res_id: 0,
res_model: "website.crm.score"
let templates: string;
export async function makeTestData(): Promise<TestData> {
if (!templates) {
templates = await loadTemplates();
}
];
const registry: typeof actionRegistry = new Registry();
(<any>registry).map = Object.assign({}, (<any>actionRegistry).map);
return {
menuInfo: makeMenuInfo(),
actions: makeActionData(),
actionRegistry: registry,
templates
};
}
export function makeMenuInfo(): MenuInfo {
const items: BaseMenuItem[] = [
{
id: 96,
name: "Discuss",
parent_id: false,
action: "ir.actions.client,131",
icon: "fa fa-comment",
children: []
},
{
id: 205,
name: "Notes",
parent_id: false,
action: "ir.actions.act_window,250",
icon: "fa fa-pen",
children: []
},
{
id: 409,
name: "CRM",
parent_id: false,
action: "ir.actions.act_window,597",
icon: "fa fa-handshake",
children: [
{
id: 418,
name: "Sales",
parent_id: 409,
action: false,
icon: false,
children: [
{
id: 423,
name: "My Pipeline",
parent_id: 418,
action: "ir.actions.act_window,597",
icon: false,
children: []
},
{
id: 812,
name: "My Quotations",
parent_id: 418,
action: "ir.actions.act_window,1051",
icon: false,
children: []
},
{
id: 419,
name: "Team Pipelines",
parent_id: 418,
action: "ir.actions.act_window,275",
icon: false,
children: []
}
]
},
{
id: 421,
name: "Leads",
parent_id: 409,
action: false,
icon: false,
children: [
{
id: 422,
name: "Leads",
parent_id: 421,
action: "ir.actions.act_window,595",
icon: false,
children: []
},
{
id: 752,
name: "Scoring Rules",
parent_id: 421,
icon: false,
action: "ir.actions.act_window,1083",
children: []
}
]
}
]
}
];
return getMenuInfo(items);
}
function makeActionData(): ActionDescription[] {
return [
{
id: 131,
type: "ir.actions.client",
target: "current",
name: "Discuss",
tag: "mail.discuss"
},
{
id: 250,
type: "ir.actions.act_window",
name: "Notes",
target: "current",
domain: false,
context: "{}",
views: [[false, "kanban"], [false, "list"], [false, "form"]],
res_id: 0,
res_model: "note.note"
},
{
id: 597,
type: "ir.actions.act_window",
name: "Pipeline",
target: "current",
domain: false,
context: { default_team_id: 1 },
views: [[2103, "kanban"], [2106, "list"], [2105, "form"]],
res_id: 0,
res_model: "crm.lead"
},
{
id: 1051,
type: "ir.actions.act_window",
name: "Quotations",
target: "current",
domain: false,
context: "{'search_default_my_quotation': 1}",
views: [
[3387, "list"],
[3385, "kanban"],
[3389, "form"],
[3382, "calendar"],
[3384, "pivot"],
[3383, "graph"]
],
res_id: 0,
res_model: "sale.order"
},
{
id: 275,
type: "ir.actions.act_window",
name: "Team Pipelines",
target: "current",
context: "{}",
domain: "[('use_opportunities', '=', True)]",
views: [[false, "kanban"], [false, "form"]],
res_id: 0,
res_model: "crm.team"
},
{
id: 595,
type: "ir.actions.act_window",
name: "Leads",
target: "current",
context:
"{ 'default_type':'lead', 'search_default_type': 'lead', 'search_default_to_process':1, }",
domain: "['|', ('type','=','lead'), ('type','=',False)]",
views: [
[2098, "list"],
[2099, "kanban"],
[2100, "calendar"],
[2108, "pivot"],
[2107, "graph"],
[false, "form"]
],
res_id: 0,
res_model: "crm.lead"
},
{
id: 1083,
type: "ir.actions.act_window",
name: "Scores",
target: "current",
context: "{}",
domain: false,
views: [[false, "list"], [false, "kanban"], [false, "form"]],
res_id: 0,
res_model: "website.crm.score"
}
];
}
function loadTemplates(): Promise<string> {
return new Promise((resolve, reject) => {
readFile("web/static/src/xml/templates.xml", "utf-8", (err, result) => {
resolve(result);
});
});
}
+70
View File
@@ -0,0 +1,70 @@
import { WEnv } from "../../src/ts/core/component";
import { QWeb } from "../../src/ts/core/qweb_vdom";
import { Registry } from "../../src/ts/core/registry";
import { idGenerator } from "../../src/ts/core/utils";
import { Env, makeEnv } from "../../src/ts/env";
import { IRouter } from "../../src/ts/services/router";
import { MenuInfo, Store } from "../../src/ts/store/store";
import { MockRouter } from "./mock_router";
import { MockServer } from "./mock_server";
import { TestData } from "./test_data";
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
export interface TestEnv extends Env {
store: Store;
}
export interface TestInfo extends Partial<TestData> {
mockRPC?(this: MockServer, route: string, params: any): Promise<any>;
router?: IRouter;
}
export function makeTestWEnv(): WEnv {
return {
qweb: new QWeb(),
getID: idGenerator()
};
}
//------------------------------------------------------------------------------
// Code
//------------------------------------------------------------------------------
export function makeTestEnv(info: TestInfo = {}): TestEnv {
const templates = info.templates || "";
const menuInfo: MenuInfo = info.menuInfo || {
menus: {},
actionMap: {},
roots: []
};
const actionRegistry = info.actionRegistry || new Registry();
const actions = info.actions || [];
const data: TestData = {
menuInfo,
actions,
actionRegistry,
templates
};
const mockServer = new MockServer(data);
function rpc(route: string, params: any): Promise<any> {
if (info.mockRPC) {
return info.mockRPC.call(mockServer, route, params);
}
return mockServer.rpc(route, params);
}
const services = {
rpc,
router: info.router || new MockRouter()
};
const store = new Store(services, menuInfo, actionRegistry);
const env = makeEnv(store, templates);
const testEnv = Object.assign({ store }, env);
return testEnv;
}
+33
View File
@@ -0,0 +1,33 @@
export function nextMicroTick(): Promise<void> {
return Promise.resolve();
}
export function nextTick(): Promise<void> {
return new Promise(resolve => setTimeout(resolve));
}
export function makeTestFixture() {
let fixture = document.createElement("div");
document.body.appendChild(fixture);
return fixture;
}
export function normalize(str: string): string {
return str.replace(/\s+/g, "");
}
interface Deferred extends Promise<any> {
resolve(val?: any): void;
reject(): void;
}
export function makeDeferred(): Deferred {
let resolve, reject;
let def = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
(<Deferred>def).resolve = resolve;
(<Deferred>def).reject = reject;
return <Deferred>def;
}
@@ -1,4 +1,5 @@
import { makeTestStore, mockFetch } from "../helpers";
import { makeTestData, makeTestEnv } from "../helpers";
import { Registry } from "../../src/ts/core/registry";
//------------------------------------------------------------------------------
// Tests
@@ -6,19 +7,34 @@ import { makeTestStore, mockFetch } from "../helpers";
test("does not reload action if already done", async () => {
const routes: string[] = [];
const store = makeTestStore({
rpc: async (route, params) => {
const data = await makeTestData();
const testEnv = makeTestEnv({
...data,
mockRPC(route, params) {
routes.push(route);
return mockFetch(route, params);
return this.rpc(route, params);
}
});
expect(routes).toEqual([]);
store.doAction(131);
testEnv.store.doAction(131);
expect(routes).toEqual(["web/action/load"]);
store.doAction(131);
testEnv.store.doAction(131);
expect(routes).toEqual(["web/action/load"]);
});
test("display a warning if client action is not in registry", async () => {
const data = await makeTestData();
data.actionRegistry = new Registry();
const testEnv = makeTestEnv(data);
await testEnv.store.doAction(131);
const notifs = testEnv.store.state.notifications;
expect(notifs.length).toBe(1);
expect(notifs[0].type).toBe("warning");
});
+20 -19
View File
@@ -1,12 +1,4 @@
import { makeTestStore, nextMicroTick } from "../helpers";
//------------------------------------------------------------------------------
// Setup and helpers
//------------------------------------------------------------------------------
function mockFetch(route: string, params: any): Promise<any> {
return Promise.resolve(`${route}`);
}
import { makeTestData, makeTestEnv, nextMicroTick } from "../helpers";
//------------------------------------------------------------------------------
// Tests
@@ -14,13 +6,20 @@ function mockFetch(route: string, params: any): Promise<any> {
describe("rpc", () => {
test("properly translate query in route", async () => {
const store = makeTestStore({ rpc: mockFetch });
const result = await store.rpc({ model: "test", method: "hey" });
expect(result).toBe("/web/dataset/call_kw/test/hey");
expect.assertions(1);
const store = makeTestEnv({
mockRPC(route, params) {
expect(route).toBe("/web/dataset/call_kw/test/hey");
return this.rpc(route, params);
}
}).store;
await store.rpc({ model: "test", method: "hey" });
});
test("trigger proper events", async () => {
const store = makeTestStore({ rpc: mockFetch });
const store = makeTestEnv().store;
const events: string[] = [];
store.on("rpc_status", null, s => {
events.push(s);
@@ -35,7 +34,7 @@ describe("rpc", () => {
describe("notifications", () => {
test("can subscribe and add notification", () => {
const store = makeTestStore();
const store = makeTestEnv().store;
expect(store.state.notifications.length).toBe(0);
const id = store.addNotification({
title: "test",
@@ -46,7 +45,7 @@ describe("notifications", () => {
});
test("can close a notification", () => {
const store = makeTestStore();
const store = makeTestEnv().store;
const id = store.addNotification({
title: "test",
@@ -60,7 +59,7 @@ describe("notifications", () => {
test("notifications closes themselves after a while", () => {
jest.useFakeTimers();
const store = makeTestStore();
const store = makeTestEnv().store;
store.addNotification({ title: "test", message: "message" });
@@ -72,7 +71,7 @@ describe("notifications", () => {
test("sticky notifications do not close themselves after a while", () => {
jest.useFakeTimers();
const store = makeTestStore();
const store = makeTestEnv().store;
store.addNotification({
title: "test",
@@ -89,7 +88,8 @@ describe("notifications", () => {
describe("state transitions", () => {
test("toggle menu", async () => {
const store = makeTestStore();
const data = await makeTestData();
const store = makeTestEnv(data).store;
expect(store.state.inHome).toBe(true);
store.toggleHomeMenu();
@@ -121,7 +121,8 @@ describe("state transitions", () => {
test("document title", async () => {
document.title = "Odoo";
const store = makeTestStore();
const data = await makeTestData();
const store = makeTestEnv(data).store;
expect(store.state.inHome).toBe(true);
expect(document.title).toBe("Odoo");
const promise = store.activateMenuItem(96);
+7 -17
View File
@@ -1,27 +1,14 @@
import { Env, makeEnv } from "../../src/ts/env";
import { Store } from "../../src/ts/store/store";
import { HomeMenu, Props } from "../../src/ts/ui/home_menu";
import * as helpers from "../helpers";
import { HomeMenu } from "../../src/ts/ui/home_menu";
import { makeTestData, makeTestEnv, makeTestFixture } from "../helpers";
//------------------------------------------------------------------------------
// Setup and helpers
//------------------------------------------------------------------------------
let fixture: HTMLElement;
let store: Store;
let env: Env;
let props: Props;
let templates: string;
beforeAll(async () => {
templates = await helpers.loadTemplates();
});
beforeEach(() => {
fixture = helpers.makeTestFixture();
store = helpers.makeTestStore();
env = makeEnv(store, templates);
props = { menuInfo: helpers.makeDemoMenuInfo() };
fixture = makeTestFixture();
});
afterEach(() => {
@@ -33,7 +20,10 @@ afterEach(() => {
//------------------------------------------------------------------------------
test("can be rendered", async () => {
const homeMenu = new HomeMenu(env, props);
const data = await makeTestData();
const testEnv = makeTestEnv(data);
const props = { menuInfo: data.menuInfo };
const homeMenu = new HomeMenu(testEnv, props);
await homeMenu.mount(fixture);
expect(fixture.innerHTML).toMatchSnapshot();
});
+9 -16
View File
@@ -1,5 +1,4 @@
import { Env, makeEnv } from "../../src/ts/env";
import { MenuInfo, Store } from "../../src/ts/store/store";
import { MenuInfo } from "../../src/ts/store/store";
import { Navbar, Props } from "../../src/ts/ui/navbar";
import * as helpers from "../helpers";
@@ -8,22 +7,16 @@ import * as helpers from "../helpers";
//------------------------------------------------------------------------------
let fixture: HTMLElement;
let store: Store;
let env: Env;
let env: helpers.TestEnv;
let props: Props;
let menuInfo: MenuInfo;
let templates: string;
beforeAll(async () => {
templates = await helpers.loadTemplates();
});
beforeEach(() => {
beforeEach(async () => {
fixture = helpers.makeTestFixture();
store = helpers.makeTestStore();
env = makeEnv(store, templates);
const data = await helpers.makeTestData();
env = helpers.makeTestEnv(data);
props = { inHome: false, app: null };
menuInfo = helpers.makeDemoMenuInfo();
menuInfo = helpers.makeMenuInfo();
});
afterEach(() => {
@@ -65,10 +58,10 @@ test("mobile mode: navbar is different", async () => {
test("clicking on left icon toggle home menu ", async () => {
props.app = menuInfo.menus[96]!;
store.state.inHome = false;
env.store.state.inHome = false;
const navbar = new Navbar(env, props);
await navbar.mount(fixture);
expect(store.state.inHome).toBe(false);
expect(env.store.state.inHome).toBe(false);
(<any>fixture).getElementsByClassName("o_title")[0].click();
expect(store.state.inHome).toBe(true);
expect(env.store.state.inHome).toBe(true);
});
+8 -16
View File
@@ -1,5 +1,4 @@
import { Env, makeEnv } from "../../src/ts/env";
import { Notification as INotification, Store } from "../../src/ts/store/store";
import { Notification as INotification } from "../../src/ts/store/store";
import { Notification } from "../../src/ts/ui/notification";
import * as helpers from "../helpers";
@@ -8,19 +7,12 @@ import * as helpers from "../helpers";
//------------------------------------------------------------------------------
let fixture: HTMLElement;
let store: Store;
let env: Env;
let templates: string;
let env: helpers.TestEnv;
beforeAll(async () => {
templates = await helpers.loadTemplates();
});
beforeEach(() => {
beforeEach(async () => {
fixture = helpers.makeTestFixture();
fixture = helpers.makeTestFixture();
store = helpers.makeTestStore();
env = makeEnv(store, templates);
const data = await helpers.makeTestData();
env = helpers.makeTestEnv(data);
});
afterEach(() => {
@@ -67,9 +59,9 @@ test("can be closed by clicking on it (if sticky)", async () => {
sticky: true
});
const navbar = new Notification(env, store.state.notifications[0]);
const navbar = new Notification(env, env.store.state.notifications[0]);
await navbar.mount(fixture);
expect(store.state.notifications.length).toBe(1);
expect(env.store.state.notifications.length).toBe(1);
(<any>fixture.getElementsByClassName("o_close")[0]).click();
expect(store.state.notifications.length).toBe(0);
expect(env.store.state.notifications.length).toBe(0);
});
+13 -20
View File
@@ -1,26 +1,15 @@
import { Env, makeEnv } from "../../src/ts/env";
import { Store } from "../../src/ts/store/store";
import { Root } from "../../src/ts/ui/root";
import * as helpers from "../helpers";
import { makeTestData, makeTestEnv } from "../helpers";
//------------------------------------------------------------------------------
// Setup and helpers
//------------------------------------------------------------------------------
let fixture: HTMLElement;
let store: Store;
let env: Env;
let templates: string;
beforeAll(async () => {
templates = await helpers.loadTemplates();
});
beforeEach(() => {
fixture = helpers.makeTestFixture();
store = helpers.makeTestStore();
env = makeEnv(store, templates);
// props = { menuInfo: helpers.makeDemoMenuInfo() };
});
afterEach(() => {
@@ -32,21 +21,23 @@ afterEach(() => {
//------------------------------------------------------------------------------
test("can be rendered (in home menu)", async () => {
const root = new Root(env, store);
const data = await makeTestData();
const testEnv = makeTestEnv(data);
const root = new Root(testEnv, testEnv.store);
await root.mount(fixture);
expect(fixture.innerHTML).toMatchSnapshot();
});
test("if url has action_id, will render action and navigate to proper menu_id", async () => {
const data = await makeTestData();
const router = new helpers.MockRouter({ action_id: "131" });
store = helpers.makeTestStore({ router });
env = makeEnv(store, templates);
const testEnv = makeTestEnv({ ...data, router });
await helpers.nextTick();
const root = new Root(env, store);
const root = new Root(testEnv, testEnv.store);
await root.mount(fixture);
await helpers.nextTick();
expect(env.services.router.getQuery()).toEqual({
expect(router.getQuery()).toEqual({
action_id: "131",
menu_id: "96"
});
@@ -54,16 +45,18 @@ test("if url has action_id, will render action and navigate to proper menu_id",
});
test("start with no action => clicks on client action => discuss is rendered", async () => {
const root = new Root(env, store);
const data = await makeTestData();
const testEnv = makeTestEnv(data);
const root = new Root(testEnv, testEnv.store);
await root.mount(fixture);
expect(env.services.router.getQuery()).toEqual({ home: true });
expect(testEnv.services.router.getQuery()).toEqual({ home: true });
// discuss menu item
await (<any>document.querySelector('[data-menu="96"]')).click();
await helpers.nextTick();
expect(fixture.innerHTML).toMatchSnapshot();
expect(env.services.router.getQuery()).toEqual({
expect(testEnv.services.router.getQuery()).toEqual({
action_id: "131",
menu_id: "96"
});