Skip to content

Commit

Permalink
[IMP] tools: update debug script, add tests
Browse files Browse the repository at this point in the history
closes #525
closes #526
  • Loading branch information
ged-odoo authored and aab-odoo committed Dec 3, 2019
1 parent ed4ab51 commit 85f26a0
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 40 deletions.
2 changes: 1 addition & 1 deletion doc/reference/misc.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The component `Portal` has no particular state, rather it is meant to be a slave
and ultimately just a way for the parent to teleport a piece of its own DOM elsewhere.

The `Portal`'s root node is always `<portal/>` and is placed where the teleported content
*would have* been. It is this element that the [teleported events](#expected-behaviors) are re-directed on.
_would have_ been. It is this element that the [teleported events](#expected-behaviors) are re-directed on.

### Example

Expand Down
7 changes: 3 additions & 4 deletions doc/tooling.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,15 @@ logging useful information is extremely valuable. There is a [javascript file](.
Once it is executed, it will log a lot of information on each component main hooks. The following code is a minified version to make it easier to copy/paste:

```
let debugSetup = {
function debugOwl(o,t){let e,n="[OWL_DEBUG]";function l(o){let t=JSON.stringify(o||{});return t.length>200&&(t=t.slice(0,200)+"..."),t}if(Object.defineProperty(o.Component,"current",{get:()=>e,set(s){e=s;const c=s.constructor.name;if(t.componentBlackList&&t.componentBlackList.test(c))return;if(t.componentWhiteList&&!t.componentWhiteList.test(c))return;let r;Object.defineProperty(e,"__owl__",{get:()=>r,set(e){!function(e,s,c){let r=`${s}<id=${c}>`,i=o=>(!t.methodBlackList||!t.methodBlackList.includes(o))&&!(t.methodWhiteList&&!t.methodWhiteList.includes(o));i("constructor")&&console.log(`${n} ${r} constructor, props=${l(e.props)}`);i("willStart")&&o.hooks.onWillStart(()=>{console.log(`${n} ${r} willStart`)});i("mounted")&&o.hooks.onMounted(()=>{console.log(`${n} ${r} mounted`)});i("willUpdateProps")&&o.hooks.onWillUpdateProps(o=>{console.log(`${n} ${r} willUpdateProps, nextprops=${l(o)}`)});i("willPatch")&&o.hooks.onWillPatch(()=>{console.log(`${n} ${r} willPatch`)});i("patched")&&o.hooks.onPatched(()=>{console.log(`${n} ${r} patched`)});i("willUnmount")&&o.hooks.onWillUnmount(()=>{console.log(`${n} ${r} willUnmount`)});const u=e.__render.bind(e);e.__render=function(...o){console.log(`${n} ${r} rendering template`),u(...o)};const d=e.render.bind(e);e.render=function(...o){return console.log(`${n} ${r} render`),d(...o)};const p=e.mount.bind(e);e.mount=function(...o){return console.log(`${n} ${r} mount`),p(...o)}}(s,c,(r=e).id)}})}}),t.logScheduler){let t=o.Component.scheduler.start,e=o.Component.scheduler.stop;o.Component.scheduler.start=function(){console.log(`${n} scheduler: start running tasks queue`),t.call(this)},o.Component.scheduler.stop=function(){console.log(`${n} scheduler: stop running tasks queue`),e.call(this)}}if(t.logStore){let t=o.Store.prototype.dispatch;o.Store.prototype.dispatch=function(o,...e){return console.log(`${n} store: action '${o}' dispatched. Payload: '${l(e)}'`),t.call(this,o,...e)}}}
debugOwl({
// componentBlackList: /App/, // regexp
// componentWhiteList: /SomeComponent/, // regexp
// methodBlackList: ["mounted"], // list of method names
// methodWhiteList: ["willStart"], // list of method names
logScheduler: false, // display/mute scheduler logs
logStore: true, // display/mute store logs
};
{let o,t="[OWL_DEBUG]";function toStr(o){let t=JSON.stringify(o||{});return t.length>200&&(t=t.slice(0,200)+"..."),t}function debugComponent(o,e,n){let l=`${e}<id=${n}>`,r=o=>(!debugSetup.methodBlackList||!debugSetup.methodBlackList.includes(o))&&!(debugSetup.methodWhiteList&&!debugSetup.methodWhiteList.includes(o));r("constructor")&&console.log(`${t} ${l} constructor, props=${toStr(o.props)}`),r("willStart")&&owl.hooks.onWillStart(()=>{console.log(`${t} ${l} willStart`)}),r("mounted")&&owl.hooks.onMounted(()=>{console.log(`${t} ${l} mounted`)}),r("willUpdateProps")&&owl.hooks.onWillUpdateProps(o=>{console.log(`${t} ${l} willUpdateProps, nextprops=${toStr(o)}`)}),r("willPatch")&&owl.hooks.onWillPatch(()=>{console.log(`${t} ${l} willPatch`)}),r("patched")&&owl.hooks.onPatched(()=>{console.log(`${t} ${l} patched`)}),r("willUnmount")&&owl.hooks.onWillUnmount(()=>{console.log(`${t} ${l} willUnmount`)});const s=o.__render.bind(o);o.__render=function(...o){console.log(`${t} ${l} rendering template`),s(...o)};const u=o.render.bind(o);o.render=function(...o){return console.log(`${t} ${l} render`),u(...o)};const c=o.mount.bind(o);o.mount=function(...o){return console.log(`${t} ${l} mount`),c(...o)}}if(Object.defineProperty(owl.Component,"current",{get:()=>o,set(t){o=t;const e=t.constructor.name;if(debugSetup.componentBlackList&&debugSetup.componentBlackList.test(e))return;if(debugSetup.componentWhiteList&&!debugSetup.componentWhiteList.test(e))return;let n;Object.defineProperty(o,"__owl__",{get:()=>n,set(o){debugComponent(t,e,(n=o).id)}})}}),debugSetup.logScheduler){let o;Object.defineProperty(owl.Component.scheduler,"isRunning",{get:()=>o,set(e){e?console.log(`${t} scheduler: start running tasks queue`):console.log(`${t} scheduler: stop running tasks queue`),o=e}})}if(debugSetup.logStore){let o=owl.Store.prototype.dispatch;owl.Store.prototype.dispatch=function(e,...n){return console.log(`${t} store: action '${e}' dispatched. Payload: '${toStr(n)}'`),o.call(this,e,...n)}}}
});
```

Note that it is certainly useful to run this code at some point in an application,
Expand Down
19 changes: 14 additions & 5 deletions src/component/scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ export class Scheduler {
this.requestAnimationFrame = requestAnimationFrame;
}

start() {
this.isRunning = true;
this.scheduleTasks();
}

stop() {
this.isRunning = false;
}

addFiber(fiber): Promise<void> {
// if the fiber was remapped into a larger rendering fiber, it may not be a
// root fiber. But we only want to register root fibers
Expand All @@ -43,7 +52,7 @@ export class Scheduler {
}
});
if (!this.isRunning) {
this.scheduleTasks();
this.start();
}
});
}
Expand Down Expand Up @@ -74,16 +83,16 @@ export class Scheduler {
return true;
});
this.tasks = tasks.concat(this.tasks);
if (this.tasks.length === 0) {
this.stop();
}
}

scheduleTasks() {
this.isRunning = true;
this.requestAnimationFrame(() => {
this.flush();
if (this.tasks.length > 0) {
if (this.isRunning) {
this.scheduleTasks();
} else {
this.isRunning = false;
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion tests/misc/portal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ describe("Portal: Events handling", () => {
<button>child</button>`;
}
class Parent extends Component<any, any> {
static components = { Portal, Child, };
static components = { Portal, Child };
static template = xml`
<div>
<Portal target="'#outside'">
Expand Down
57 changes: 57 additions & 0 deletions tests/tooling/debug_script_1.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* We can only make one test per file, since the debug tool modify in place
* the owl object in a way that is difficult to undo.
*/

import { debugOwl } from "../../tools/debug";
import * as owl from "../../src/index";

import { Component, Env } from "../../src/component/component";
import { xml } from "../../src/tags";
import { useState } from "../../src/hooks";
import { makeTestFixture, makeTestEnv, nextTick } from "../helpers";

let fixture: HTMLElement = makeTestFixture();
let env: Env = makeTestEnv();
Component.env = env;

debugOwl(owl, {});

test("can log full lifecycle", async () => {
const steps: string[] = [];
const log = console.log;
console.log = arg => steps.push(arg);

class Child extends Component<any, any> {
static template = xml`<div>child</div>`;
}

class Parent extends Component<any, any> {
static template = xml`<div><Child t-if="state.flag"/></div>`;
static components = { Child };
state = useState({ flag: false });
}

const parent = new Parent(null, {});
await parent.mount(fixture);

parent.state.flag = true;
await nextTick();

expect(steps).toEqual([
"[OWL_DEBUG] Parent<id=1> constructor, props={}",
"[OWL_DEBUG] Parent<id=1> mount",
"[OWL_DEBUG] Parent<id=1> willStart",
"[OWL_DEBUG] Parent<id=1> rendering template",
"[OWL_DEBUG] Parent<id=1> mounted",
"[OWL_DEBUG] Parent<id=1> render",
"[OWL_DEBUG] Parent<id=1> rendering template",
"[OWL_DEBUG] Child<id=2> constructor, props={}",
"[OWL_DEBUG] Child<id=2> willStart",
"[OWL_DEBUG] Child<id=2> rendering template",
"[OWL_DEBUG] Parent<id=1> willPatch",
"[OWL_DEBUG] Child<id=2> mounted",
"[OWL_DEBUG] Parent<id=1> patched"
]);
console.log = log;
});
50 changes: 50 additions & 0 deletions tests/tooling/debug_script_2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* We can only make one test per file, since the debug tool modify in place
* the owl object in a way that is difficult to undo.
*/

import { debugOwl } from "../../tools/debug";
import * as owl from "../../src/index";

import { Component, Env } from "../../src/component/component";
import { xml } from "../../src/tags";
import { makeTestFixture, makeTestEnv } from "../helpers";

let fixture: HTMLElement = makeTestFixture();
let env: Env = makeTestEnv();
Component.env = env;

debugOwl(owl, { logScheduler: true });

test("can log scheduler start and stop", async () => {
const steps: string[] = [];
const log = console.log;
console.log = arg => steps.push(arg);

class Child extends Component<any, any> {
static template = xml`<div>child</div>`;
}

class Parent extends Component<any, any> {
static template = xml`<div><Child /></div>`;
static components = { Child };
}

const parent = new Parent(null, {});
await parent.mount(fixture);

expect(steps).toEqual([
"[OWL_DEBUG] Parent<id=1> constructor, props={}",
"[OWL_DEBUG] Parent<id=1> mount",
"[OWL_DEBUG] Parent<id=1> willStart",
"[OWL_DEBUG] scheduler: start running tasks queue",
"[OWL_DEBUG] Parent<id=1> rendering template",
"[OWL_DEBUG] Child<id=2> constructor, props={}",
"[OWL_DEBUG] Child<id=2> willStart",
"[OWL_DEBUG] Child<id=2> rendering template",
"[OWL_DEBUG] Child<id=2> mounted",
"[OWL_DEBUG] Parent<id=1> mounted",
"[OWL_DEBUG] scheduler: stop running tasks queue"
]);
console.log = log;
});
File renamed without changes.
60 changes: 31 additions & 29 deletions tools/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,7 @@
* to log lot of helpful information on how Owl components behave.
*/

let debugSetup = {
// componentBlackList: /App/, // regexp
// componentWhiteList: /SomeComponent/, // regexp
// methodBlackList: ["mounted"], // list of method names
// methodWhiteList: ["willStart"], // list of method names
logScheduler: true, // display/mute scheduler logs
logStore: true // display/mute store logs
};
{
function debugOwl(owl, options) {
let prefix = "[OWL_DEBUG]";
let current;
Object.defineProperty(owl.Component, "current", {
Expand All @@ -23,10 +15,10 @@ let debugSetup = {
set(comp) {
current = comp;
const name = comp.constructor.name;
if (debugSetup.componentBlackList && debugSetup.componentBlackList.test(name)) {
if (options.componentBlackList && options.componentBlackList.test(name)) {
return;
}
if (debugSetup.componentWhiteList && !debugSetup.componentWhiteList.test(name)) {
if (options.componentWhiteList && !options.componentWhiteList.test(name)) {
return;
}
let __owl__;
Expand All @@ -53,10 +45,10 @@ let debugSetup = {
function debugComponent(component, name, id) {
let fullName = `${name}<id=${id}>`;
let shouldDebug = method => {
if (debugSetup.methodBlackList && debugSetup.methodBlackList.includes(method)) {
if (options.methodBlackList && options.methodBlackList.includes(method)) {
return false;
}
if (debugSetup.methodWhiteList && !debugSetup.methodWhiteList.includes(method)) {
if (options.methodWhiteList && !options.methodWhiteList.includes(method)) {
return false;
}
return true;
Expand Down Expand Up @@ -111,27 +103,37 @@ let debugSetup = {
};
}

if (debugSetup.logScheduler) {
let isRunning;
Object.defineProperty(owl.Component.scheduler, "isRunning", {
get() {
return isRunning;
},
set(val) {
if (val) {
console.log(`${prefix} scheduler: start running tasks queue`);
} else {
console.log(`${prefix} scheduler: stop running tasks queue`);
}
isRunning = val;
}
});
if (options.logScheduler) {
let start = owl.Component.scheduler.start;
let stop = owl.Component.scheduler.stop;
owl.Component.scheduler.start = function () {
console.log(`${prefix} scheduler: start running tasks queue`);
start.call(this);
};
owl.Component.scheduler.stop = function () {
console.log(`${prefix} scheduler: stop running tasks queue`);
stop.call(this);
};
}
if (debugSetup.logStore) {
if (options.logStore) {
let dispatch = owl.Store.prototype.dispatch;
owl.Store.prototype.dispatch = function(action, ...payload) {
console.log(`${prefix} store: action '${action}' dispatched. Payload: '${toStr(payload)}'`);
return dispatch.call(this, action, ...payload);
};
}
}


// This debug function can then be used like this:
//
// debugOwl(owl, {
// componentBlackList: /App/, // regexp
// componentWhiteList: /SomeComponent/, // regexp
// methodBlackList: ["mounted"], // list of method names
// methodWhiteList: ["willStart"], // list of method names
// logScheduler: true, // display/mute scheduler logs
// logStore: true // display/mute store logs
// });

module.exports.debugOwl = debugOwl;

0 comments on commit 85f26a0

Please sign in to comment.