import { module, test } from "qunit";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import widgetHbs from "discourse/widgets/hbs-compiler";
import Widget from "discourse/widgets/widget";
import ClassicComponent from "@ember/component";
import RenderGlimmer from "discourse/widgets/render-glimmer";
class DemoWidget extends Widget {
static actionTriggered = false;
tagName = "div.my-widget";
html(attrs) {
return [
this.attach("button", {
label: "rerender",
className: "triggerRerender",
action: "dummyAction",
}),
new RenderGlimmer(
this,
"div.glimmer-wrapper",
hbs`
arg1={{@data.arg1}} dynamicArg={{@data.dynamicArg}}
`,
{
...attrs,
actionForComponentToTrigger: this.actionForComponentToTrigger,
}
),
];
}
dummyAction() {}
actionForComponentToTrigger() {
DemoWidget.actionTriggered = true;
}
}
class DemoComponent extends ClassicComponent {
static eventLog = [];
classNames = ["demo-component"];
init() {
DemoComponent.eventLog.push("init");
super.init(...arguments);
}
didInsertElement() {
DemoComponent.eventLog.push("didInsertElement");
}
willDestroyElement() {
DemoComponent.eventLog.push("willDestroyElement");
}
didReceiveAttrs() {
DemoComponent.eventLog.push("didReceiveAttrs");
}
willDestroy() {
DemoComponent.eventLog.push("willDestroy");
}
layout = hbs``;
}
module("Integration | Component | Widget | render-glimmer", function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
DemoComponent.eventLog = [];
DemoWidget.actionTriggered = false;
this.registry.register("widget:demo-widget", DemoWidget);
this.registry.register("component:demo-component", DemoComponent);
});
hooks.afterEach(function () {
this.registry.unregister("widget:demo-widget");
this.registry.unregister("component:demo-component");
});
test("argument handling", async function (assert) {
await render(
hbs`
`
);
assert.true(exists("div.my-widget"), "widget is rendered");
assert.true(exists("div.glimmer-content"), "glimmer content is rendered");
assert.strictEqual(
query("div.glimmer-content").innerText,
"arg1=val1 dynamicArg=",
"arguments are passed through"
);
await fillIn("input.dynamic-value-input", "somedynamicvalue");
assert.strictEqual(
query("div.glimmer-content").innerText,
"arg1=val1 dynamicArg=",
"changed arguments do not change before rerender"
);
await click(".my-widget button");
assert.strictEqual(
query("div.glimmer-content").innerText,
"arg1=val1 dynamicArg=somedynamicvalue",
"changed arguments are applied after rerender"
);
});
test("child component lifecycle", async function (assert) {
assert.deepEqual(
DemoComponent.eventLog,
[],
"component event log starts empty"
);
await render(
hbs`
{{#unless (eq this.dynamicValue 'hidden')}}
{{/unless}}`
);
assert.true(exists("div.my-widget"), "widget is rendered");
assert.true(exists("div.glimmer-content"), "glimmer content is rendered");
assert.true(exists("div.demo-component"), "demo component is rendered");
assert.deepEqual(
DemoComponent.eventLog,
["init", "didReceiveAttrs", "didInsertElement"],
"component is initialized correctly"
);
DemoComponent.eventLog = [];
await fillIn("input.dynamic-value-input", "somedynamicvalue");
assert.deepEqual(
DemoComponent.eventLog,
[],
"component is not notified of attr change before widget rerender"
);
await click(".my-widget button");
assert.deepEqual(
DemoComponent.eventLog,
["didReceiveAttrs"],
"component is notified of attr change during widget rerender"
);
DemoComponent.eventLog = [];
await fillIn("input.dynamic-value-input", "hidden");
assert.deepEqual(
DemoComponent.eventLog,
["willDestroyElement", "willDestroy"],
"destroy hooks are run correctly"
);
DemoComponent.eventLog = [];
await fillIn("input.dynamic-value-input", "visibleAgain");
assert.deepEqual(
DemoComponent.eventLog,
["init", "didReceiveAttrs", "didInsertElement"],
"component can be reinitialized"
);
});
test("trigger widget actions from component", async function (assert) {
assert.false(
DemoWidget.actionTriggered,
"widget event has not been triggered yet"
);
await render(
hbs`
{{#unless (eq this.dynamicValue 'hidden')}}
{{/unless}}`
);
assert.true(
exists("div.demo-component button"),
"component button is rendered"
);
await click("div.demo-component button");
assert.true(DemoWidget.actionTriggered, "widget event is triggered");
});
test("developer ergonomics", function (assert) {
assert.throws(
() => {
// eslint-disable-next-line no-new
new RenderGlimmer(this, "div", ``);
},
/`template` should be a template compiled via `ember-cli-htmlbars`/,
"it raises a useful error when passed a string instead of a template"
);
assert.throws(
() => {
// eslint-disable-next-line no-new
new RenderGlimmer(this, "div", widgetHbs`{{using-the-wrong-compiler}}`);
},
/`template` should be a template compiled via `ember-cli-htmlbars`/,
"it raises a useful error when passed a widget-hbs-compiler template"
);
// eslint-disable-next-line no-new
new RenderGlimmer(this, "div", hbs``);
assert.true(true, "it doesn't raise an error for correct params");
});
});