From 38f307ef57399aa2deedd73fde28997f3697e800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 19 Mar 2019 11:48:30 +0100 Subject: [PATCH] implement updateEnv feature --- src/component.ts | 17 +++++++++++ tests/component.test.ts | 65 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/component.ts b/src/component.ts index 8befe2e6..c552c118 100644 --- a/src/component.ts +++ b/src/component.ts @@ -196,6 +196,23 @@ export class Component< return true; } + /** + * This method is the correct way to update the environment of a widget. Doing + * this will cause a full rerender of the widget and its children, so this is + * an operation that should not be done frequently. + * + * A good usecase for updating the environment would be to update some mostly + * static config keys, such as a boolean to determine if we are in mobile + * mode or not. + */ + async updateEnv(nextEnv: Partial): Promise { + if (this.__widget__.parent && this.__widget__.parent.env === this.env) { + this.env = Object.create(this.env); + } + Object.assign(this.env, nextEnv); + return this.render(); + } + async updateProps(nextProps: Props): Promise { if (nextProps === this.__widget__.renderProps) { await this.__widget__.renderPromise; diff --git a/tests/component.test.ts b/tests/component.test.ts index 056800f5..025cb0c4 100644 --- a/tests/component.test.ts +++ b/tests/component.test.ts @@ -36,7 +36,7 @@ afterEach(() => { fixture.remove(); }); -class Widget extends Component {} +class Widget extends Component {} function children(w: Widget): Widget[] { const childrenMap = w.__widget__.children; @@ -1086,3 +1086,66 @@ describe("async rendering", () => { ); }); }); + +describe("updating environment", () => { + test("can update widget env", async () => { + const widget = new Widget(env); + expect(widget.env).toBe(env); + await widget.updateEnv({ somekey: 4 }); + expect(widget.env).toBe(env); + expect((widget).env.somekey).toBe(4); + }); + + test("updating child env does not modify parent env", async () => { + class ParentWidget extends Widget { + inlineTemplate = `
`; + widgets = { child: Widget }; + } + const parent = new ParentWidget(env); + await parent.mount(fixture); + const child = children(parent)[0]; + expect(child.env).toBe(parent.env); + await child.updateEnv({ somekey: 4 }); + expect(child.env).not.toBe(parent.env); + expect((parent).env.somekey).toBeUndefined(); + }); + + test("updating parent env does modify child env", async () => { + class ParentWidget extends Widget { + inlineTemplate = `
`; + widgets = { child: Widget }; + } + const parent = new ParentWidget(env); + await parent.mount(fixture); + const child = children(parent)[0]; + expect(child.env.somekey).toBeUndefined(); + await parent.updateEnv({ somekey: 4 }); + expect(child.env.somekey).toBe(4); + }); + + test("updating parent env does modify child env, part 2", async () => { + class ParentWidget extends Widget { + inlineTemplate = `
`; + widgets = { child: Widget }; + } + const parent = new ParentWidget(env); + await parent.mount(fixture); + const child = children(parent)[0]; + expect(child.env.somekey).toBeUndefined(); + await child.updateEnv({ somekey: 4 }); + await parent.updateEnv({ someotherkey: 4 }); + expect(child.env.someotherkey).toBe(4); + }); + + test("updating env force a rerender", async () => { + class TestWidget extends Widget { + inlineTemplate = `
`; + } + (env).someKey = "hey"; + const widget = new TestWidget(env); + await widget.mount(fixture); + expect(fixture.innerHTML).toBe("
hey
"); + await widget.updateEnv({ someKey: "rerendered" }); + expect(fixture.innerHTML).toBe("
rerendered
"); + }); +});