DEV: Re-evaluate plugin outlet `shouldRender` when inputs change
This commit updates the PluginOutlet component so that it calculates the list of connectors in an autotracking context. Accessing arguments or any other `@tracked` values during `shouldRender` means that the set of connectors will be re-calculated whenever those tracked values change.
This commit is contained in:
parent
30025a96f3
commit
9ce58c7e36
|
@ -56,10 +56,8 @@ export default class PluginOutletComponent extends GlimmerComponentWithDeprecate
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
get connectors() {
|
||||||
super(...arguments);
|
return renderedConnectorsFor(
|
||||||
|
|
||||||
this.connectors = renderedConnectorsFor(
|
|
||||||
this.args.name,
|
this.args.name,
|
||||||
this.outletArgsWithDeprecations,
|
this.outletArgsWithDeprecations,
|
||||||
this.context
|
this.context
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
import {
|
|
||||||
acceptance,
|
|
||||||
count,
|
|
||||||
exists,
|
|
||||||
query,
|
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
|
||||||
import { click, visit } from "@ember/test-helpers";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { extraConnectorClass } from "discourse/lib/plugin-connectors";
|
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
|
||||||
import { test } from "qunit";
|
|
||||||
import { registerTemporaryModule } from "discourse/tests/helpers/temporary-module-helper";
|
|
||||||
|
|
||||||
const PREFIX = "discourse/plugins/some-plugin/templates/connectors";
|
|
||||||
|
|
||||||
acceptance("Plugin Outlet - Connector Class", function (needs) {
|
|
||||||
needs.hooks.beforeEach(() => {
|
|
||||||
extraConnectorClass("user-profile-primary/hello", {
|
|
||||||
actions: {
|
|
||||||
sayHello() {
|
|
||||||
this.set("hello", `${this.hello || ""}hello!`);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
extraConnectorClass("user-profile-primary/hi", {
|
|
||||||
setupComponent() {
|
|
||||||
this.appEvents.on("hi:sayHi", this, this.say);
|
|
||||||
},
|
|
||||||
|
|
||||||
teardownComponent() {
|
|
||||||
this.appEvents.off("hi:sayHi", this, this.say);
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
say() {
|
|
||||||
this.set("hi", "hi!");
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
sayHi() {
|
|
||||||
this.appEvents.trigger("hi:sayHi");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
extraConnectorClass("user-profile-primary/dont-render", {
|
|
||||||
shouldRender(args) {
|
|
||||||
return args.model.get("username") !== "eviltrout";
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
registerTemporaryModule(
|
|
||||||
`${PREFIX}/user-profile-primary/hello`,
|
|
||||||
hbs`<span class='hello-username'>{{model.username}}</span>
|
|
||||||
<button class='say-hello' {{on "click" (action "sayHello")}}></button>
|
|
||||||
<button class='say-hello-using-this' {{on "click" this.sayHello}}></button>
|
|
||||||
<span class='hello-result'>{{hello}}</span>`
|
|
||||||
);
|
|
||||||
registerTemporaryModule(
|
|
||||||
`${PREFIX}/user-profile-primary/hi`,
|
|
||||||
hbs`<button class='say-hi' {{on "click" (action "sayHi")}}></button>
|
|
||||||
<span class='hi-result'>{{hi}}</span>`
|
|
||||||
);
|
|
||||||
registerTemporaryModule(
|
|
||||||
`${PREFIX}/user-profile-primary/dont-render`,
|
|
||||||
hbs`I'm not rendered!`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Renders a template into the outlet", async function (assert) {
|
|
||||||
await visit("/u/eviltrout");
|
|
||||||
assert.strictEqual(
|
|
||||||
count(".user-profile-primary-outlet.hello"),
|
|
||||||
1,
|
|
||||||
"it has class names"
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
!exists(".user-profile-primary-outlet.dont-render"),
|
|
||||||
"doesn't render"
|
|
||||||
);
|
|
||||||
|
|
||||||
await click(".say-hello");
|
|
||||||
assert.strictEqual(
|
|
||||||
query(".hello-result").innerText,
|
|
||||||
"hello!",
|
|
||||||
"actions delegate properly"
|
|
||||||
);
|
|
||||||
await click(".say-hello-using-this");
|
|
||||||
assert.strictEqual(
|
|
||||||
query(".hello-result").innerText,
|
|
||||||
"hello!hello!",
|
|
||||||
"actions are made available on `this` and are bound correctly"
|
|
||||||
);
|
|
||||||
|
|
||||||
await click(".say-hi");
|
|
||||||
assert.strictEqual(
|
|
||||||
query(".hi-result").innerText,
|
|
||||||
"hi!",
|
|
||||||
"actions delegate properly"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
import { module, test } from "qunit";
|
||||||
|
import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||||
|
import { click, render, settled } from "@ember/test-helpers";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { extraConnectorClass } from "discourse/lib/plugin-connectors";
|
||||||
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
|
import { registerTemporaryModule } from "discourse/tests/helpers/temporary-module-helper";
|
||||||
|
import { getOwner } from "discourse-common/lib/get-owner";
|
||||||
|
|
||||||
|
const PREFIX = "discourse/plugins/some-plugin/templates/connectors";
|
||||||
|
|
||||||
|
module("Integration | Component | plugin-outlet", function (hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
hooks.beforeEach(function () {
|
||||||
|
extraConnectorClass("test-name/hello", {
|
||||||
|
actions: {
|
||||||
|
sayHello() {
|
||||||
|
this.set("hello", `${this.hello || ""}hello!`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
extraConnectorClass("test-name/hi", {
|
||||||
|
setupComponent() {
|
||||||
|
this.appEvents.on("hi:sayHi", this, this.say);
|
||||||
|
},
|
||||||
|
|
||||||
|
teardownComponent() {
|
||||||
|
this.appEvents.off("hi:sayHi", this, this.say);
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
say() {
|
||||||
|
this.set("hi", "hi!");
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
sayHi() {
|
||||||
|
this.appEvents.trigger("hi:sayHi");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
extraConnectorClass("test-name/conditional-render", {
|
||||||
|
shouldRender(args, context) {
|
||||||
|
return args.shouldDisplay || context.siteSettings.always_display;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTemporaryModule(
|
||||||
|
`${PREFIX}/test-name/hello`,
|
||||||
|
hbs`<span class='hello-username'>{{username}}</span>
|
||||||
|
<button class='say-hello' {{on "click" (action "sayHello")}}></button>
|
||||||
|
<button class='say-hello-using-this' {{on "click" this.sayHello}}></button>
|
||||||
|
<span class='hello-result'>{{hello}}</span>`
|
||||||
|
);
|
||||||
|
registerTemporaryModule(
|
||||||
|
`${PREFIX}/test-name/hi`,
|
||||||
|
hbs`<button class='say-hi' {{on "click" (action "sayHi")}}></button>
|
||||||
|
<span class='hi-result'>{{hi}}</span>`
|
||||||
|
);
|
||||||
|
registerTemporaryModule(
|
||||||
|
`${PREFIX}/test-name/conditional-render`,
|
||||||
|
hbs`<span class="conditional-render">I only render sometimes</span>`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Renders a template into the outlet", async function (assert) {
|
||||||
|
this.set("shouldDisplay", false);
|
||||||
|
await render(
|
||||||
|
hbs`<PluginOutlet @name="test-name" @args={{hash shouldDisplay=this.shouldDisplay}} />`
|
||||||
|
);
|
||||||
|
assert.strictEqual(count(".hello-username"), 1, "renders the hello outlet");
|
||||||
|
assert.false(
|
||||||
|
exists(".conditional-render"),
|
||||||
|
"doesn't render conditional outlet"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click(".say-hello");
|
||||||
|
assert.strictEqual(
|
||||||
|
query(".hello-result").innerText,
|
||||||
|
"hello!",
|
||||||
|
"actions delegate properly"
|
||||||
|
);
|
||||||
|
await click(".say-hello-using-this");
|
||||||
|
assert.strictEqual(
|
||||||
|
query(".hello-result").innerText,
|
||||||
|
"hello!hello!",
|
||||||
|
"actions are made available on `this` and are bound correctly"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click(".say-hi");
|
||||||
|
assert.strictEqual(
|
||||||
|
query(".hi-result").innerText,
|
||||||
|
"hi!",
|
||||||
|
"actions delegate properly"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Reevaluates shouldRender for argument changes", async function (assert) {
|
||||||
|
this.set("shouldDisplay", false);
|
||||||
|
await render(
|
||||||
|
hbs`<PluginOutlet @name="test-name" @args={{hash shouldDisplay=this.shouldDisplay}} />`
|
||||||
|
);
|
||||||
|
assert.false(
|
||||||
|
exists(".conditional-render"),
|
||||||
|
"doesn't render conditional outlet"
|
||||||
|
);
|
||||||
|
|
||||||
|
this.set("shouldDisplay", true);
|
||||||
|
await settled();
|
||||||
|
assert.true(exists(".conditional-render"), "renders conditional outlet");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Reevaluates shouldRender for other autotracked changes", async function (assert) {
|
||||||
|
this.set("shouldDisplay", false);
|
||||||
|
await render(
|
||||||
|
hbs`<PluginOutlet @name="test-name" @args={{hash shouldDisplay=this.shouldDisplay}} />`
|
||||||
|
);
|
||||||
|
assert.false(
|
||||||
|
exists(".conditional-render"),
|
||||||
|
"doesn't render conditional outlet"
|
||||||
|
);
|
||||||
|
|
||||||
|
getOwner(this).lookup("service:site-settings").always_display = true;
|
||||||
|
await settled();
|
||||||
|
assert.true(exists(".conditional-render"), "renders conditional outlet");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Other outlets are not re-rendered", async function (assert) {
|
||||||
|
this.set("shouldDisplay", false);
|
||||||
|
await render(
|
||||||
|
hbs`<PluginOutlet @name="test-name" @args={{hash shouldDisplay=this.shouldDisplay}} />`
|
||||||
|
);
|
||||||
|
|
||||||
|
const otherOutletElement = query(".hello-username");
|
||||||
|
otherOutletElement.someUniqueProperty = true;
|
||||||
|
|
||||||
|
this.set("shouldDisplay", true);
|
||||||
|
await settled();
|
||||||
|
assert.true(exists(".conditional-render"), "renders conditional outlet");
|
||||||
|
|
||||||
|
assert.true(
|
||||||
|
query(".hello-username").someUniqueProperty,
|
||||||
|
"other outlet is left untouched"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue