DEV: Modernize component tests (#17368)

* Use QUnit `module` instead of `discourseModule`
* Use QUnit `test` instead of `componentTest`
* Use angle-bracket syntax
* Remove jQuery usage
* Improve assertions (and actually fix some of them)
This commit is contained in:
Jarek Radosz
2022-07-11 12:29:44 +02:00
committed by GitHub
parent 5b70b67e78
commit 189bebb2e4
122 changed files with 8203 additions and 9999 deletions

View File

@ -159,6 +159,10 @@ export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
}); });
this._uppyInstance.on("upload", (data) => { this._uppyInstance.on("upload", (data) => {
if (this.isDestroying || this.isDestroyed) {
return;
}
this._addNeedProcessing(data.fileIDs.length); this._addNeedProcessing(data.fileIDs.length);
const files = data.fileIDs.map((fileId) => const files = data.fileIDs.map((fileId) =>
this._uppyInstance.getFile(fileId) this._uppyInstance.getFile(fileId)
@ -257,6 +261,10 @@ export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
this._uppyInstance.on("complete", () => { this._uppyInstance.on("complete", () => {
run(() => { run(() => {
if (this.isDestroying || this.isDestroyed) {
return;
}
this.appEvents.trigger(`upload-mixin:${this.id}:all-uploads-complete`); this.appEvents.trigger(`upload-mixin:${this.id}:all-uploads-complete`);
this._reset(); this._reset();
}); });

View File

@ -5,16 +5,28 @@ import TopicTrackingState from "discourse/models/topic-tracking-state";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { autoLoadModules } from "discourse/initializers/auto-load-modules"; import { autoLoadModules } from "discourse/initializers/auto-load-modules";
import QUnit, { test } from "qunit"; import QUnit, { test } from "qunit";
import { setupRenderingTest as emberSetupRenderingTest } from "ember-qunit"; import { setupRenderingTest as emberSetupRenderingTest } from "ember-qunit";
import { currentSettings } from "discourse/tests/helpers/site-settings";
import { clearResolverOptions } from "discourse-common/resolver";
import { testCleanup } from "discourse/tests/helpers/qunit-helpers";
export function setupRenderingTest(hooks) { export function setupRenderingTest(hooks) {
emberSetupRenderingTest(hooks); emberSetupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
if (!hooks.usingDiscourseModule) {
this.siteSettings = currentSettings();
if (!this.registry) {
this.registry = this.owner.__registry__;
}
this.container = this.owner;
clearResolverOptions();
}
this.site = Site.current(); this.site = Site.current();
this.session = Session.current(); this.session = Session.current();
this.container = this.owner;
const currentUser = User.create({ const currentUser = User.create({
username: "eviltrout", username: "eviltrout",
@ -41,9 +53,16 @@ export function setupRenderingTest(hooks) {
); );
autoLoadModules(this.owner, this.registry); autoLoadModules(this.owner, this.registry);
this.owner.lookup("service:store");
$.fn.autocomplete = function () {}; $.fn.autocomplete = function () {};
}); });
if (!hooks.usingDiscourseModule) {
hooks.afterEach(function () {
testCleanup(this.container);
});
}
} }
export default function (name, hooks, opts) { export default function (name, hooks, opts) {

View File

@ -138,7 +138,7 @@ export function applyPretender(name, server, helper) {
} }
// Add clean up code here to run after every test // Add clean up code here to run after every test
function testCleanup(container, app) { export function testCleanup(container, app) {
if (_initialized.has(QUnit.config.current.testId)) { if (_initialized.has(QUnit.config.current.testId)) {
if (!app) { if (!app) {
app = getApplication(); app = getApplication();
@ -223,6 +223,7 @@ export function discourseModule(name, options) {
this.moduleName = name; this.moduleName = name;
hooks.usingDiscourseModule = true;
options.call(this, hooks); options.call(this, hooks);
}); });

View File

@ -1,48 +1,37 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { count, exists } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | ace-editor", function (hooks) { module("Integration | Component | ace-editor", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("css editor", { test("css editor", async function (assert) {
template: hbs`{{ace-editor mode="css"}}`, await render(hbs`<AceEditor @mode="css" />`);
test(assert) { assert.ok(exists(".ace_editor"), "it renders the ace editor");
assert.ok(exists(".ace_editor"), "it renders the ace editor");
},
}); });
componentTest("html editor", { test("html editor", async function (assert) {
template: hbs`{{ace-editor mode="html" content="<b>wat</b>"}}`, await render(hbs`<AceEditor @mode="html" @content="<b>wat</b>" />`);
test(assert) { assert.ok(exists(".ace_editor"), "it renders the ace editor");
assert.ok(exists(".ace_editor"), "it renders the ace editor");
},
}); });
componentTest("sql editor", { test("sql editor", async function (assert) {
template: hbs`{{ace-editor mode="sql" content="SELECT * FROM users"}}`, await render(hbs`<AceEditor @mode="sql" @content="SELECT * FROM users" />`);
test(assert) { assert.ok(exists(".ace_editor"), "it renders the ace editor");
assert.ok(exists(".ace_editor"), "it renders the ace editor");
},
}); });
componentTest("disabled editor", { test("disabled editor", async function (assert) {
template: hbs` await render(hbs`
{{ace-editor mode="sql" content="SELECT * FROM users" disabled=true}} <AceEditor @mode="sql" @content="SELECT * FROM users" @disabled=true />
`, `);
test(assert) {
assert.ok(exists(".ace_editor"), "it renders the ace editor"); assert.ok(exists(".ace_editor"), "it renders the ace editor");
assert.equal( assert.strictEqual(
queryAll(".ace-wrapper[data-disabled]").length, count(".ace-wrapper[data-disabled]"),
1, 1,
"it has a data-disabled attr" "it has a data-disabled attr"
); );
},
}); });
}); });

View File

@ -1,24 +1,18 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, exists } from "discourse/tests/helpers/qunit-helpers"; import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module("Integration | Component | activation-controls", function (hooks) {
"Integration | Component | activation-controls", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("hides change email button", { test("hides change email button", async function (assert) {
template: hbs`{{activation-controls}}`, this.siteSettings.enable_local_logins = false;
beforeEach() { this.siteSettings.email_editable = false;
this.siteSettings.enable_local_logins = false;
this.siteSettings.email_editable = false;
},
test(assert) { await render(hbs`<ActivationControls />`);
assert.ok(!exists("button.edit-email"));
}, assert.ok(!exists("button.edit-email"));
}); });
} });
);

View File

@ -1,190 +1,166 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
count,
discourseModule,
exists,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import { click } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender from "discourse/tests/helpers/create-pretender"; import pretender from "discourse/tests/helpers/create-pretender";
discourseModule("Integration | Component | admin-report", function (hooks) { module("Integration | Component | admin-report", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("default", { test("default", async function (assert) {
template: hbs`{{admin-report dataSourceName='signups'}}`, await render(hbs`<AdminReport @dataSourceName="signups" />`);
async test(assert) { assert.ok(exists(".admin-report.signups"));
assert.ok(exists(".admin-report.signups"));
assert.ok(exists(".admin-report.signups", "it defaults to table mode")); assert.ok(exists(".admin-report.signups", "it defaults to table mode"));
assert.strictEqual( assert.strictEqual(
queryAll(".header .item.report").text().trim(), query(".header .item.report").innerText.trim(),
"Signups", "Signups",
"it has a title" "it has a title"
); );
assert.strictEqual( assert.strictEqual(
queryAll(".header .info").attr("data-tooltip"), query(".header .info").getAttribute("data-tooltip"),
"New account registrations for this period", "New account registrations for this period",
"it has a description" "it has a description"
); );
assert.strictEqual( assert.strictEqual(
queryAll(".admin-report-table thead tr th:first-child .title") query(
.text() ".admin-report-table thead tr th:first-child .title"
.trim(), ).innerText.trim(),
"Day", "Day",
"it has col headers" "it has col headers"
); );
assert.strictEqual( assert.strictEqual(
queryAll(".admin-report-table thead tr th:nth-child(2) .title") query(
.text() ".admin-report-table thead tr th:nth-child(2) .title"
.trim(), ).innerText.trim(),
"Count", "Count",
"it has col headers" "it has col headers"
); );
assert.strictEqual( assert.strictEqual(
queryAll(".admin-report-table tbody tr:nth-child(1) td:nth-child(1)") query(
.text() ".admin-report-table tbody tr:nth-child(1) td:nth-child(1)"
.trim(), ).innerText.trim(),
"June 16, 2018", "June 16, 2018",
"it has rows" "it has rows"
); );
assert.strictEqual( assert.strictEqual(
queryAll(".admin-report-table tbody tr:nth-child(1) td:nth-child(2)") query(
.text() ".admin-report-table tbody tr:nth-child(1) td:nth-child(2)"
.trim(), ).innerText.trim(),
"12", "12",
"it has rows" "it has rows"
); );
assert.ok(exists(".total-row"), "it has totals"); assert.ok(exists(".total-row"), "it has totals");
await click(".admin-report-table-header.y .sort-btn"); await click(".admin-report-table-header.y .sort-btn");
assert.strictEqual( assert.strictEqual(
queryAll(".admin-report-table tbody tr:nth-child(1) td:nth-child(2)") query(
.text() ".admin-report-table tbody tr:nth-child(1) td:nth-child(2)"
.trim(), ).innerText.trim(),
"7", "7",
"it can sort rows" "it can sort rows"
); );
},
}); });
componentTest("options", { test("options", async function (assert) {
template: hbs`{{admin-report dataSourceName='signups' reportOptions=options}}`, this.set("options", {
table: {
perPage: 4,
total: false,
},
});
beforeEach() { await render(
this.set("options", { hbs`<AdminReport @dataSourceName="signups" @reportOptions={{this.options}} />`
table: { );
perPage: 4,
total: false, assert.ok(exists(".pagination"), "it paginates the results");
assert.strictEqual(
count(".pagination button"),
3,
"it creates the correct number of pages"
);
assert.notOk(exists(".totals-sample-table"), "it hides totals");
});
test("switch modes", async function (assert) {
await render(
hbs`<AdminReport @dataSourceName="signups" @showFilteringUI={{true}} />`
);
await click(".mode-btn.chart");
assert.notOk(exists(".admin-report-table"), "it removes the table");
assert.ok(exists(".admin-report-chart"), "it shows the chart");
});
test("timeout", async function (assert) {
await render(hbs`<AdminReport @dataSourceName="signups_timeout" />`);
assert.ok(exists(".alert-error.timeout"), "it displays a timeout error");
});
test("no data", async function (assert) {
await render(hbs`<AdminReport @dataSourceName="posts" />`);
assert.ok(exists(".no-data"), "it displays a no data alert");
});
test("exception", async function (assert) {
await render(hbs`<AdminReport @dataSourceName="signups_exception" />`);
assert.ok(exists(".alert-error.exception"), "it displays an error");
});
test("rate limited", async function (assert) {
pretender.get("/admin/reports/bulk", () => {
return [
429,
{ "Content-Type": "application/json" },
{
errors: [
"You’ve performed this action too many times. Please wait 10 seconds before trying again.",
],
error_type: "rate_limit",
extras: { wait_seconds: 10 },
}, },
}); ];
}, });
test(assert) { await render(hbs`<AdminReport @dataSourceName="signups_rate_limited" />`);
assert.ok(exists(".pagination"), "it paginates the results");
assert.strictEqual(
count(".pagination button"),
3,
"it creates the correct number of pages"
);
assert.notOk(exists(".totals-sample-table"), "it hides totals"); assert.ok(
}, exists(".alert-error.rate-limited"),
"it displays a rate limited error"
);
}); });
componentTest("switch modes", { test("post edits", async function (assert) {
template: hbs`{{admin-report dataSourceName='signups' showFilteringUI=true}}`, await render(hbs`<AdminReport @dataSourceName="post_edits" />`);
async test(assert) { assert.ok(
await click(".mode-btn.chart"); exists(".admin-report.post-edits"),
"it displays the post edits report"
assert.notOk(exists(".admin-report-table"), "it removes the table"); );
assert.ok(exists(".admin-report-chart"), "it shows the chart");
},
}); });
componentTest("timeout", { test("not found", async function (assert) {
template: hbs`{{admin-report dataSourceName='signups_timeout'}}`, await render(hbs`<AdminReport @dataSourceName="not_found" />`);
test(assert) { assert.ok(
assert.ok(exists(".alert-error.timeout"), "it displays a timeout error"); exists(".alert-error.not-found"),
}, "it displays a not found error"
}); );
componentTest("no data", {
template: hbs`{{admin-report dataSourceName='posts'}}`,
test(assert) {
assert.ok(exists(".no-data"), "it displays a no data alert");
},
});
componentTest("exception", {
template: hbs`{{admin-report dataSourceName='signups_exception'}}`,
test(assert) {
assert.ok(exists(".alert-error.exception"), "it displays an error");
},
});
componentTest("rate limited", {
beforeEach() {
pretender.get("/admin/reports/bulk", () => {
return [
429,
{ "Content-Type": "application/json" },
{
errors: [
"You’ve performed this action too many times. Please wait 10 seconds before trying again.",
],
error_type: "rate_limit",
extras: { wait_seconds: 10 },
},
];
});
},
template: hbs`{{admin-report dataSourceName='signups_rate_limited'}}`,
test(assert) {
assert.ok(
exists(".alert-error.rate-limited"),
"it displays a rate limited error"
);
},
});
componentTest("post edits", {
template: hbs`{{admin-report dataSourceName='post_edits'}}`,
test(assert) {
assert.ok(
exists(".admin-report.post-edits"),
"it displays the post edits report"
);
},
});
componentTest("not found", {
template: hbs`{{admin-report dataSourceName='not_found'}}`,
test(assert) {
assert.ok(
exists(".alert-error.not-found"),
"it displays a not found error"
);
},
}); });
}); });

View File

@ -1,78 +1,60 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import I18n from "I18n"; import I18n from "I18n";
import { click } from "@ember/test-helpers";
discourseModule( module("Integration | Component | admin-user-field-item", function (hooks) {
"Integration | Component | admin-user-field-item", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("user field without an id", { test("user field without an id", async function (assert) {
template: hbs`{{admin-user-field-item userField=userField}}`, await render(hbs`<AdminUserFieldItem @userField={{this.userField}} />`);
async test(assert) { assert.ok(exists(".save"), "displays editing mode");
assert.ok(exists(".save"), "displays editing mode"); });
},
test("cancel action", async function (assert) {
this.set("userField", { id: 1, field_type: "text" });
this.set("isEditing", true);
await render(
hbs`<AdminUserFieldItem @isEditing={{this.isEditing}} @destroyAction={{this.destroyAction}} @userField={{this.userField}} />`
);
await click(".cancel");
assert.ok(exists(".edit"));
});
test("edit action", async function (assert) {
this.set("userField", { id: 1, field_type: "text" });
await render(
hbs`<AdminUserFieldItem @destroyAction={{this.destroyAction}} @userField={{this.userField}} />`
);
await click(".edit");
assert.ok(exists(".save"));
});
test("user field with an id", async function (assert) {
this.set("userField", {
id: 1,
field_type: "text",
name: "foo",
description: "what is foo",
}); });
componentTest("cancel action", { await render(hbs`<AdminUserFieldItem @userField={{this.userField}} />`);
template: hbs`{{admin-user-field-item isEditing=isEditing destroyAction=destroyAction userField=userField}}`,
beforeEach() { assert.strictEqual(query(".name").innerText, this.userField.name);
this.set("userField", { id: 1, field_type: "text" }); assert.strictEqual(
this.set("isEditing", true); query(".description").innerText,
}, this.userField.description
);
async test(assert) { assert.strictEqual(
await click(".cancel"); query(".field-type").innerText,
assert.ok(exists(".edit")); I18n.t("admin.user_fields.field_types.text")
}, );
}); });
});
componentTest("edit action", {
template: hbs`{{admin-user-field-item destroyAction=destroyAction userField=userField}}`,
beforeEach() {
this.set("userField", { id: 1, field_type: "text" });
},
async test(assert) {
await click(".edit");
assert.ok(exists(".save"));
},
});
componentTest("user field with an id", {
template: hbs`{{admin-user-field-item userField=userField}}`,
beforeEach() {
this.set("userField", {
id: 1,
field_type: "text",
name: "foo",
description: "what is foo",
});
},
async test(assert) {
assert.equal(query(".name").innerText, this.userField.name);
assert.equal(
query(".description").innerText,
this.userField.description
);
assert.equal(
query(".field-type").innerText,
I18n.t("admin.user_fields.field_types.text")
);
},
});
}
);

View File

@ -1,14 +1,11 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import pretender from "discourse/tests/helpers/create-pretender"; import { createFile } from "discourse/tests/helpers/qunit-helpers";
import {
createFile,
discourseModule,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender from "discourse/tests/helpers/create-pretender";
discourseModule("Integration | Component | avatar-uploader", function (hooks) { module("Integration | Component | avatar-uploader", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
@ -17,25 +14,24 @@ discourseModule("Integration | Component | avatar-uploader", function (hooks) {
}); });
}); });
componentTest("default", { test("default", async function (assert) {
template: hbs`{{avatar-uploader const done = assert.async();
id="avatar-uploader" this.set("done", () => {
done=done assert.ok(true, "action is called after avatar is uploaded");
}}`, done();
});
async test(assert) { await render(hbs`
const done = assert.async(); <AvatarUploader
@id="avatar-uploader"
@done={{this.done}}
/>
`);
this.set("done", () => { await this.container
assert.ok(true, "action is called after avatar is uploaded"); .lookup("service:app-events")
done(); .trigger("upload-mixin:avatar-uploader:add-files", [
}); createFile("avatar.png"),
]);
await this.container
.lookup("service:app-events")
.trigger("upload-mixin:avatar-uploader:add-files", [
createFile("avatar.png"),
]);
},
}); });
}); });

View File

@ -1,105 +1,81 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | badge-button", function (hooks) { module("Integration | Component | badge-button", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("disabled badge", { test("disabled badge", async function (assert) {
template: hbs`{{badge-button badge=badge}}`, this.set("badge", { enabled: false });
beforeEach() { await render(hbs`<BadgeButton @badge={{this.badge}} />`);
this.set("badge", { enabled: false });
},
async test(assert) { assert.ok(exists(".user-badge.disabled"));
assert.ok(exists(".user-badge.disabled"));
},
}); });
componentTest("enabled badge", { test("enabled badge", async function (assert) {
template: hbs`{{badge-button badge=badge}}`, this.set("badge", { enabled: true });
beforeEach() { await render(hbs`<BadgeButton @badge={{this.badge}} />`);
this.set("badge", { enabled: true });
},
async test(assert) { assert.notOk(exists(".user-badge.disabled"));
assert.notOk(exists(".user-badge.disabled"));
},
}); });
componentTest("data-badge-name", { test("data-badge-name", async function (assert) {
template: hbs`{{badge-button badge=badge}}`, this.set("badge", { name: "foo" });
beforeEach() { await render(hbs`<BadgeButton @badge={{this.badge}} />`);
this.set("badge", { name: "foo" });
},
async test(assert) { assert.ok(exists('.user-badge[data-badge-name="foo"]'));
assert.ok(exists('.user-badge[data-badge-name="foo"]'));
},
}); });
componentTest("title", { test("title", async function (assert) {
template: hbs`{{badge-button badge=badge}}`, this.set("badge", { description: "a <a href>good</a> run" });
beforeEach() { await render(hbs`<BadgeButton @badge={{this.badge}} />`);
this.set("badge", { description: "a <a href>good</a> run" });
},
async test(assert) { assert.strictEqual(
assert.equal(query(".user-badge").title, "a good run", "it strips html"); query(".user-badge").title,
"a good run",
"it strips html"
);
this.set("badge", { description: "a bad run" }); this.set("badge", { description: "a bad run" });
assert.equal( assert.strictEqual(
query(".user-badge").title, query(".user-badge").title,
"a bad run", "a bad run",
"it updates title when changing description" "it updates title when changing description"
); );
},
}); });
componentTest("icon", { test("icon", async function (assert) {
template: hbs`{{badge-button badge=badge}}`, this.set("badge", { icon: "times" });
beforeEach() { await render(hbs`<BadgeButton @badge={{this.badge}} />`);
this.set("badge", { icon: "times" });
},
async test(assert) { assert.ok(exists(".d-icon.d-icon-times"));
assert.ok(exists(".d-icon.d-icon-times"));
},
}); });
componentTest("accepts block", { test("accepts block", async function (assert) {
template: hbs`{{#badge-button badge=badge}}<span class="test"></span>{{/badge-button}}`, this.set("badge", {});
beforeEach() { await render(hbs`
this.set("badge", {}); <BadgeButton @badge={{this.badge}}>
}, <span class="test"></span>
</BadgeButton>
`);
async test(assert) { assert.ok(exists(".test"));
assert.ok(exists(".test"));
},
}); });
componentTest("badgeTypeClassName", { test("badgeTypeClassName", async function (assert) {
template: hbs`{{badge-button badge=badge}}`, this.set("badge", { badgeTypeClassName: "foo" });
beforeEach() { await render(hbs`<BadgeButton @badge={{this.badge}} />`);
this.set("badge", { badgeTypeClassName: "foo" });
},
async test(assert) { assert.ok(exists(".user-badge.foo"));
assert.ok(exists(".user-badge.foo"));
},
}); });
}); });

View File

@ -1,46 +1,42 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import EmberObject from "@ember/object";
import { click } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender from "discourse/tests/helpers/create-pretender"; import pretender from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
import EmberObject from "@ember/object";
discourseModule("Integration | Component | badge-title", function (hooks) { module("Integration | Component | badge-title", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("badge title", { test("badge title", async function (assert) {
template: hbs` this.set("subject", selectKit());
{{badge-title selectableUserBadges=selectableUserBadges}} this.set("selectableUserBadges", [
`, EmberObject.create({
id: 0,
badge: { name: "(none)" },
}),
EmberObject.create({
id: 42,
badge_id: 102,
badge: { name: "Test" },
}),
]);
beforeEach() { pretender.put("/u/eviltrout/preferences/badge_title", () => [
this.set("subject", selectKit()); 200,
this.set("selectableUserBadges", [ { "Content-Type": "application/json" },
EmberObject.create({ {},
id: 0, ]);
badge: { name: "(none)" },
}),
EmberObject.create({
id: 42,
badge_id: 102,
badge: { name: "Test" },
}),
]);
},
async test(assert) { await render(hbs`
pretender.put("/u/eviltrout/preferences/badge_title", () => [ <BadgeTitle @selectableUserBadges={{this.selectableUserBadges}} />
200, `);
{ "Content-Type": "application/json" },
{}, await this.subject.expand();
]); await this.subject.selectRowByValue(42);
await this.subject.expand(); await click(".btn");
await this.subject.selectRowByValue(42);
await click(".btn"); assert.strictEqual(this.currentUser.title, "Test");
assert.strictEqual(this.currentUser.title, "Test");
},
}); });
}); });

View File

@ -1,87 +1,71 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import Bookmark from "discourse/models/bookmark"; import Bookmark from "discourse/models/bookmark";
import I18n from "I18n"; import I18n from "I18n";
import { formattedReminderTime } from "discourse/lib/bookmark"; import { formattedReminderTime } from "discourse/lib/bookmark";
import { tomorrow } from "discourse/lib/time-utils"; import { tomorrow } from "discourse/lib/time-utils";
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import hbs from "htmlbars-inline-precompile";
import {
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
discourseModule("Integration | Component | bookmark-icon", function (hooks) { module("Integration | Component | bookmark-icon", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("with reminder", { test("with reminder", async function (assert) {
template: hbs`{{bookmark-icon bookmark=bookmark}}`, this.setProperties({
bookmark: Bookmark.create({
reminder_at: tomorrow(this.currentUser.timezone),
name: "some name",
}),
});
beforeEach() { await render(hbs`<BookmarkIcon @bookmark={{this.bookmark}} />`);
this.setProperties({
bookmark: Bookmark.create({
reminder_at: tomorrow(this.currentUser.timezone),
name: "some name",
}),
});
},
async test(assert) { assert.ok(
assert.ok( exists(".d-icon-discourse-bookmark-clock.bookmark-icon__bookmarked")
exists(".d-icon-discourse-bookmark-clock.bookmark-icon__bookmarked") );
); assert.strictEqual(
assert.strictEqual( query(".svg-icon-title").title,
query(".svg-icon-title")["title"], I18n.t("bookmarks.created_with_reminder_generic", {
I18n.t("bookmarks.created_with_reminder_generic", { date: formattedReminderTime(
date: formattedReminderTime( this.bookmark.reminder_at,
this.bookmark.reminder_at, this.currentUser.timezone
this.currentUser.timezone ),
), name: "some name",
name: "some name", })
}) );
);
},
}); });
componentTest("no reminder", { test("no reminder", async function (assert) {
template: hbs`{{bookmark-icon bookmark=bookmark}}`, this.set(
"bookmark",
Bookmark.create({
name: "some name",
})
);
beforeEach() { await render(hbs`<BookmarkIcon @bookmark={{this.bookmark}} />`);
this.set(
"bookmark",
Bookmark.create({
name: "some name",
})
);
},
async test(assert) { assert.ok(exists(".d-icon-bookmark.bookmark-icon__bookmarked"));
assert.ok(exists(".d-icon-bookmark.bookmark-icon__bookmarked")); assert.strictEqual(
assert.strictEqual( query(".svg-icon-title").title,
query(".svg-icon-title")["title"], I18n.t("bookmarks.created_generic", {
I18n.t("bookmarks.created_generic", { name: "some name",
name: "some name", })
}) );
);
},
}); });
componentTest("null bookmark", { test("null bookmark", async function (assert) {
template: hbs`{{bookmark-icon bookmark=bookmark}}`, this.setProperties({
bookmark: null,
});
beforeEach() { await render(hbs`<BookmarkIcon @bookmark={{this.bookmark}} />`);
this.setProperties({
bookmark: null,
});
},
async test(assert) { assert.ok(exists(".d-icon-bookmark.bookmark-icon"));
assert.ok(exists(".d-icon-bookmark.bookmark-icon")); assert.strictEqual(
assert.strictEqual( query(".svg-icon-title").title,
query(".svg-icon-title")["title"], I18n.t("bookmarks.create")
I18n.t("bookmarks.create") );
);
},
}); });
}); });

View File

@ -1,20 +1,12 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | bookmark", function (hooks) { module("Integration | Component | bookmark", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
const template = hbs`{{bookmark
model=model
afterSave=afterSave
afterDelete=afterDelete
onCloseWithoutSaving=onCloseWithoutSaving
registerOnCloseHandler=registerOnCloseHandler
closeModal=closeModal}}`;
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.setProperties({ this.setProperties({
model: {}, model: {},
@ -26,22 +18,27 @@ discourseModule("Integration | Component | bookmark", function (hooks) {
}); });
}); });
componentTest("prefills the custom reminder type date and time", { test("prefills the custom reminder type date and time", async function (assert) {
template, let name = "test";
let reminderAt = "2020-05-15T09:45:00";
this.model = { id: 1, name, reminderAt };
beforeEach() { await render(hbs`
let name = "test"; <Bookmark
let reminderAt = "2020-05-15T09:45:00"; @model={{this.model}}
this.model = { id: 1, name, reminderAt }; @afterSave={{this.afterSave}}
}, @afterDelete={{this.afterDelete}}
@onCloseWithoutSaving={{this.onCloseWithoutSaving}}
@registerOnCloseHandler={{this.registerOnCloseHandler}}
@closeModal={{this.closeModal}}
/>
`);
test(assert) { assert.strictEqual(query("#bookmark-name").value, "test");
assert.strictEqual(query("#bookmark-name").value, "test"); assert.strictEqual(
assert.strictEqual( query("#custom-date > .date-picker").value,
query("#custom-date > .date-picker").value, "2020-05-15"
"2020-05-15" );
); assert.strictEqual(query("#custom-time").value, "09:45");
assert.strictEqual(query("#custom-time").value, "09:45");
},
}); });
}); });

View File

@ -0,0 +1,33 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import Category from "discourse/models/category";
module("Integration | Component | category-badge helper", function (hooks) {
setupRenderingTest(hooks);
test("displays category", async function (assert) {
this.set("category", Category.findById(1));
await render(hbs`{{category-badge category}}`);
assert.strictEqual(
query(".category-name").innerText.trim(),
this.category.name
);
});
test("options.link", async function (assert) {
this.set("category", Category.findById(1));
await render(hbs`{{category-badge category link=true}}`);
assert.ok(
exists(
`a.badge-wrapper[href="/c/${this.category.slug}/${this.category.id}"]`
)
);
});
});

View File

@ -1,45 +0,0 @@
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import {
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import Category from "discourse/models/category";
discourseModule("Integration | Component | category-badge", function (hooks) {
setupRenderingTest(hooks);
componentTest("displays category", {
template: hbs`{{category-badge category}}`,
beforeEach() {
this.set("category", Category.findById(1));
},
async test(assert) {
assert.equal(
query(".category-name").innerText.trim(),
this.category.name
);
},
});
componentTest("options.link", {
template: hbs`{{category-badge category link=true}}`,
beforeEach() {
this.set("category", Category.findById(1));
},
async test(assert) {
assert.ok(
exists(
`a.badge-wrapper[href="/c/${this.category.slug}/${this.category.id}"]`
)
);
},
});
});

View File

@ -1,52 +1,48 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender from "discourse/tests/helpers/create-pretender"; import pretender from "discourse/tests/helpers/create-pretender";
import { resetCache } from "pretty-text/upload-short-url"; import { resetCache } from "pretty-text/upload-short-url";
discourseModule("Integration | Component | cook-text", function (hooks) { module("Integration | Component | cook-text", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("renders markdown", { hooks.afterEach(function () {
template: hbs`<CookText @rawText="_foo_" @class="post-body" />`, resetCache();
test(assert) {
const html = query(".post-body").innerHTML.trim();
assert.strictEqual(html, "<p><em>foo</em></p>");
},
}); });
componentTest("resolves short URLs", { test("renders markdown", async function (assert) {
template: hbs`<CookText @rawText="![an image](upload://a.png)" @class="post-body" />`, await render(hbs`<CookText @rawText="_foo_" @class="post-body" />`);
beforeEach() { const html = query(".post-body").innerHTML.trim();
pretender.post("/uploads/lookup-urls", () => { assert.strictEqual(html, "<p><em>foo</em></p>");
return [ });
200,
{ "Content-Type": "application/json" },
[
{
short_url: "upload://a.png",
url: "/images/avatar.png",
short_path: "/images/d-logo-sketch.png",
},
],
];
});
},
afterEach() { test("resolves short URLs", async function (assert) {
resetCache(); pretender.post("/uploads/lookup-urls", () => {
}, return [
200,
{ "Content-Type": "application/json" },
[
{
short_url: "upload://a.png",
url: "/images/avatar.png",
short_path: "/images/d-logo-sketch.png",
},
],
];
});
test(assert) { await render(
const html = query(".post-body").innerHTML.trim(); hbs`<CookText @rawText="![an image](upload://a.png)" @class="post-body" />`
assert.strictEqual( );
html,
'<p><img src="/images/avatar.png" alt="an image"></p>' const html = query(".post-body").innerHTML.trim();
); assert.strictEqual(
}, html,
'<p><img src="/images/avatar.png" alt="an image"></p>'
);
}); });
}); });

View File

@ -1,304 +1,244 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render, triggerKeyEvent } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import { triggerKeyEvent } from "@ember/test-helpers";
import I18n from "I18n"; import I18n from "I18n";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | d-button", function (hooks) { module("Integration | Component | d-button", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("icon only button", { test("icon only button", async function (assert) {
template: hbs`{{d-button icon="plus" tabindex="3"}}`, await render(hbs`<DButton @icon="plus" tabindex="3" />`);
test(assert) { assert.ok(exists("button.btn.btn-icon.no-text"), "it has all the classes");
assert.ok( assert.ok(exists("button .d-icon.d-icon-plus"), "it has the icon");
exists("button.btn.btn-icon.no-text"), assert.strictEqual(
"it has all the classes" query("button").getAttribute("tabindex"),
); "3",
assert.ok(exists("button .d-icon.d-icon-plus"), "it has the icon"); "it has the tabindex"
assert.strictEqual( );
queryAll("button").attr("tabindex"),
"3",
"it has the tabindex"
);
},
}); });
componentTest("icon and text button", { test("icon and text button", async function (assert) {
template: hbs`{{d-button icon="plus" label="topic.create"}}`, await render(hbs`<DButton @icon="plus" @label="topic.create" />`);
test(assert) { assert.ok(exists("button.btn.btn-icon-text"), "it has all the classes");
assert.ok(exists("button.btn.btn-icon-text"), "it has all the classes"); assert.ok(exists("button .d-icon.d-icon-plus"), "it has the icon");
assert.ok(exists("button .d-icon.d-icon-plus"), "it has the icon"); assert.ok(exists("button span.d-button-label"), "it has the label");
assert.ok(exists("button span.d-button-label"), "it has the label");
},
}); });
componentTest("text only button", { test("text only button", async function (assert) {
template: hbs`{{d-button label="topic.create"}}`, await render(hbs`<DButton @label="topic.create" />`);
test(assert) { assert.ok(exists("button.btn.btn-text"), "it has all the classes");
assert.ok(exists("button.btn.btn-text"), "it has all the classes"); assert.ok(exists("button span.d-button-label"), "it has the label");
assert.ok(exists("button span.d-button-label"), "it has the label");
},
}); });
componentTest("form attribute", { test("form attribute", async function (assert) {
template: hbs`{{d-button form="login-form"}}`, await render(hbs`<DButton @form="login-form" />`);
test(assert) { assert.ok(exists("button[form=login-form]"), "it has the form attribute");
assert.ok(exists("button[form=login-form]"), "it has the form attribute");
},
}); });
componentTest("link-styled button", { test("link-styled button", async function (assert) {
template: hbs`{{d-button display="link"}}`, await render(hbs`<DButton @display="link" />`);
test(assert) { assert.ok(exists("button.btn-link:not(.btn)"), "it has the right classes");
assert.ok(
exists("button.btn-link:not(.btn)"),
"it has the right classes"
);
},
}); });
componentTest("isLoading button", { test("isLoading button", async function (assert) {
template: hbs`{{d-button isLoading=isLoading}}`, this.set("isLoading", true);
beforeEach() { await render(hbs`<DButton @isLoading={{this.isLoading}} />`);
this.set("isLoading", true);
},
test(assert) { assert.ok(
assert.ok( exists("button.is-loading .loading-icon"),
exists("button.is-loading .loading-icon"), "it has a spinner showing"
"it has a spinner showing" );
); assert.ok(
assert.ok( exists("button[disabled]"),
exists("button[disabled]"), "while loading the button is disabled"
"while loading the button is disabled" );
);
this.set("isLoading", false); this.set("isLoading", false);
assert.notOk( assert.notOk(
exists("button .loading-icon"), exists("button .loading-icon"),
"it doesn't have a spinner showing" "it doesn't have a spinner showing"
); );
assert.ok( assert.ok(
exists("button:not([disabled])"), exists("button:not([disabled])"),
"while not loading the button is enabled" "while not loading the button is enabled"
); );
},
}); });
componentTest("button without isLoading attribute", { test("button without isLoading attribute", async function (assert) {
template: hbs`{{d-button}}`, await render(hbs`<DButton />`);
test(assert) { assert.notOk(
assert.notOk( exists("button.is-loading"),
exists("button.is-loading"), "it doesn't have class is-loading"
"it doesn't have class is-loading" );
); assert.notOk(
assert.notOk( exists("button .loading-icon"),
exists("button .loading-icon"), "it doesn't have a spinner showing"
"it doesn't have a spinner showing" );
); assert.notOk(exists("button[disabled]"), "it isn't disabled");
assert.notOk(exists("button[disabled]"), "it isn't disabled");
},
}); });
componentTest("isLoading button explicitly set to undefined state", { test("isLoading button explicitly set to undefined state", async function (assert) {
template: hbs`{{d-button isLoading=isLoading}}`, this.set("isLoading");
beforeEach() { await render(hbs`<DButton @isLoading={{this.isLoading}} />`);
this.set("isLoading");
},
test(assert) { assert.notOk(
assert.notOk( exists("button.is-loading"),
exists("button.is-loading"), "it doesn't have class is-loading"
"it doesn't have class is-loading" );
); assert.notOk(
assert.notOk( exists("button .loading-icon"),
exists("button .loading-icon"), "it doesn't have a spinner showing"
"it doesn't have a spinner showing" );
); assert.notOk(exists("button[disabled]"), "it isn't disabled");
assert.notOk(exists("button[disabled]"), "it isn't disabled");
},
}); });
componentTest("disabled button", { test("disabled button", async function (assert) {
template: hbs`{{d-button disabled=disabled}}`, this.set("disabled", true);
beforeEach() { await render(hbs`<DButton @disabled={{this.disabled}} />`);
this.set("disabled", true);
},
test(assert) { assert.ok(exists("button[disabled]"), "the button is disabled");
assert.ok(exists("button[disabled]"), "the button is disabled");
this.set("disabled", false); this.set("disabled", false);
assert.ok(exists("button:not([disabled])"), "the button is enabled");
assert.ok(exists("button:not([disabled])"), "the button is enabled");
},
}); });
componentTest("aria-label", { test("aria-label", async function (assert) {
template: hbs`{{d-button ariaLabel=ariaLabel translatedAriaLabel=translatedAriaLabel}}`, I18n.translations[I18n.locale].js.test = { fooAriaLabel: "foo" };
beforeEach() { await render(
I18n.translations[I18n.locale].js.test = { fooAriaLabel: "foo" }; hbs`<DButton @ariaLabel={{this.ariaLabel}} @translatedAriaLabel={{this.translatedAriaLabel}} />`
}, );
test(assert) { this.set("ariaLabel", "test.fooAriaLabel");
this.set("ariaLabel", "test.fooAriaLabel");
assert.strictEqual( assert.strictEqual(
query("button").getAttribute("aria-label"), query("button").getAttribute("aria-label"),
I18n.t("test.fooAriaLabel") I18n.t("test.fooAriaLabel")
); );
this.setProperties({ this.setProperties({
ariaLabel: null, ariaLabel: null,
translatedAriaLabel: "bar", translatedAriaLabel: "bar",
}); });
assert.strictEqual(query("button").getAttribute("aria-label"), "bar"); assert.strictEqual(query("button").getAttribute("aria-label"), "bar");
},
}); });
componentTest("title", { test("title", async function (assert) {
template: hbs`{{d-button title=title translatedTitle=translatedTitle}}`, I18n.translations[I18n.locale].js.test = { fooTitle: "foo" };
beforeEach() { await render(
I18n.translations[I18n.locale].js.test = { fooTitle: "foo" }; hbs`<DButton @title={{this.title}} @translatedTitle={{this.translatedTitle}} />`
}, );
test(assert) { this.set("title", "test.fooTitle");
this.set("title", "test.fooTitle"); assert.strictEqual(
assert.strictEqual( query("button").getAttribute("title"),
query("button").getAttribute("title"), I18n.t("test.fooTitle")
I18n.t("test.fooTitle") );
);
this.setProperties({ this.setProperties({
title: null, title: null,
translatedTitle: "bar", translatedTitle: "bar",
}); });
assert.strictEqual(query("button").getAttribute("title"), "bar"); assert.strictEqual(query("button").getAttribute("title"), "bar");
},
}); });
componentTest("label", { test("label", async function (assert) {
template: hbs`{{d-button label=label translatedLabel=translatedLabel}}`, I18n.translations[I18n.locale].js.test = { fooLabel: "foo" };
beforeEach() { await render(
I18n.translations[I18n.locale].js.test = { fooLabel: "foo" }; hbs`<DButton @label={{this.label}} @translatedLabel={{this.translatedLabel}} />`
}, );
test(assert) { this.set("label", "test.fooLabel");
this.set("label", "test.fooLabel");
assert.strictEqual( assert.strictEqual(
queryAll("button .d-button-label").text(), query("button .d-button-label").innerText,
I18n.t("test.fooLabel") I18n.t("test.fooLabel")
); );
this.setProperties({ this.setProperties({
label: null, label: null,
translatedLabel: "bar", translatedLabel: "bar",
}); });
assert.strictEqual(queryAll("button .d-button-label").text(), "bar"); assert.strictEqual(query("button .d-button-label").innerText, "bar");
},
}); });
componentTest("aria-expanded", { test("aria-expanded", async function (assert) {
template: hbs`{{d-button ariaExpanded=ariaExpanded}}`, await render(hbs`<DButton @ariaExpanded={{this.ariaExpanded}} />`);
test(assert) { assert.strictEqual(query("button").getAttribute("aria-expanded"), null);
assert.strictEqual(query("button").getAttribute("aria-expanded"), null);
this.set("ariaExpanded", true); this.set("ariaExpanded", true);
assert.strictEqual(query("button").getAttribute("aria-expanded"), "true"); assert.strictEqual(query("button").getAttribute("aria-expanded"), "true");
this.set("ariaExpanded", false); this.set("ariaExpanded", false);
assert.strictEqual( assert.strictEqual(query("button").getAttribute("aria-expanded"), "false");
query("button").getAttribute("aria-expanded"),
"false"
);
this.set("ariaExpanded", "false"); this.set("ariaExpanded", "false");
assert.strictEqual(query("button").getAttribute("aria-expanded"), null); assert.strictEqual(query("button").getAttribute("aria-expanded"), null);
this.set("ariaExpanded", "true"); this.set("ariaExpanded", "true");
assert.strictEqual(query("button").getAttribute("aria-expanded"), null); assert.strictEqual(query("button").getAttribute("aria-expanded"), null);
},
}); });
componentTest("aria-controls", { test("aria-controls", async function (assert) {
template: hbs`{{d-button ariaControls=ariaControls}}`, await render(hbs`<DButton @ariaControls={{this.ariaControls}} />`);
test(assert) { this.set("ariaControls", "foo-bar");
this.set("ariaControls", "foo-bar"); assert.strictEqual(
assert.strictEqual( query("button").getAttribute("aria-controls"),
query("button").getAttribute("aria-controls"), "foo-bar"
"foo-bar" );
);
},
}); });
componentTest("onKeyDown callback", { test("onKeyDown callback", async function (assert) {
template: hbs`{{d-button action=action onKeyDown=onKeyDown}}`, this.set("foo", null);
this.set("onKeyDown", () => {
this.set("foo", "bar");
});
this.set("action", () => {
this.set("foo", "baz");
});
beforeEach() { await render(
this.set("foo", null); hbs`<DButton @action={{this.action}} @onKeyDown={{this.onKeyDown}} />`
this.set("onKeyDown", () => { );
this.set("foo", "bar");
});
this.set("action", () => {
this.set("foo", "baz");
});
},
async test(assert) { await triggerKeyEvent(".btn", "keydown", 32);
await triggerKeyEvent(".btn", "keydown", 32); assert.strictEqual(this.foo, "bar");
assert.strictEqual(this.foo, "bar"); await triggerKeyEvent(".btn", "keydown", 13);
assert.strictEqual(this.foo, "bar");
await triggerKeyEvent(".btn", "keydown", 13);
assert.strictEqual(this.foo, "bar");
},
}); });
componentTest("press Enter", { test("press Enter", async function (assert) {
template: hbs`{{d-button action=action}}`, this.set("foo", null);
this.set("action", () => {
this.set("foo", "bar");
});
beforeEach() { await render(hbs`<DButton @action={{this.action}} />`);
this.set("foo", null);
this.set("action", () => {
this.set("foo", "bar");
});
},
async test(assert) { await triggerKeyEvent(".btn", "keydown", 32);
await triggerKeyEvent(".btn", "keydown", 32); assert.strictEqual(this.foo, null);
assert.strictEqual(this.foo, null); await triggerKeyEvent(".btn", "keydown", 13);
assert.strictEqual(this.foo, "bar");
await triggerKeyEvent(".btn", "keydown", 13);
assert.strictEqual(this.foo, "bar");
},
}); });
}); });

View File

@ -1,89 +1,81 @@
import { click, fillIn, settled } from "@ember/test-helpers"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { click, fillIn, render, settled } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test";
import { import {
discourseModule, chromeTest,
exists, exists,
paste, paste,
query, query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers"; } from "discourse/tests/helpers/qunit-helpers";
import { import {
getTextareaSelection, getTextareaSelection,
setTextareaSelection, setTextareaSelection,
} from "discourse/tests/helpers/textarea-selection-helper"; } from "discourse/tests/helpers/textarea-selection-helper";
import hbs from "htmlbars-inline-precompile";
import I18n from "I18n"; import I18n from "I18n";
import { clearToolbarCallbacks } from "discourse/components/d-editor"; import { clearToolbarCallbacks } from "discourse/components/d-editor";
import formatTextWithSelection from "discourse/tests/helpers/d-editor-helper"; import formatTextWithSelection from "discourse/tests/helpers/d-editor-helper";
import hbs from "htmlbars-inline-precompile";
import { next } from "@ember/runloop"; import { next } from "@ember/runloop";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
discourseModule("Integration | Component | d-editor", function (hooks) { module("Integration | Component | d-editor", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("preview updates with markdown", { hooks.afterEach(function () {
template: hbs`{{d-editor value=value}}`, clearToolbarCallbacks();
async test(assert) {
assert.ok(exists(".d-editor-button-bar"));
await fillIn(".d-editor-input", "hello **world**");
assert.strictEqual(this.value, "hello **world**");
assert.strictEqual(
queryAll(".d-editor-preview").html().trim(),
"<p>hello <strong>world</strong></p>"
);
},
}); });
componentTest("links in preview are not tabbable", { test("preview updates with markdown", async function (assert) {
template: hbs`{{d-editor value=value}}`, await render(hbs`<DEditor @value={{this.value}} />`);
async test(assert) { assert.ok(exists(".d-editor-button-bar"));
await fillIn(".d-editor-input", "[discourse](https://www.discourse.org)"); await fillIn(".d-editor-input", "hello **world**");
assert.strictEqual( assert.strictEqual(this.value, "hello **world**");
queryAll(".d-editor-preview").html().trim(), assert.strictEqual(
'<p><a href="https://www.discourse.org" tabindex="-1">discourse</a></p>' query(".d-editor-preview").innerHTML.trim(),
); "<p>hello <strong>world</strong></p>"
}, );
}); });
componentTest("preview sanitizes HTML", { test("links in preview are not tabbable", async function (assert) {
template: hbs`{{d-editor value=value}}`, await render(hbs`<DEditor @value={{this.value}} />`);
async test(assert) { await fillIn(".d-editor-input", "[discourse](https://www.discourse.org)");
await fillIn(".d-editor-input", `"><svg onload="prompt(/xss/)"></svg>`);
assert.strictEqual( assert.strictEqual(
queryAll(".d-editor-preview").html().trim(), query(".d-editor-preview").innerHTML.trim(),
'<p>"&gt;</p>' '<p><a href="https://www.discourse.org" tabindex="-1">discourse</a></p>'
); );
},
}); });
componentTest("updating the value refreshes the preview", { test("preview sanitizes HTML", async function (assert) {
template: hbs`{{d-editor value=value}}`, await render(hbs`<DEditor @value={{this.value}} />`);
beforeEach() { await fillIn(".d-editor-input", `"><svg onload="prompt(/xss/)"></svg>`);
this.set("value", "evil trout"); assert.strictEqual(
}, query(".d-editor-preview").innerHTML.trim(),
'<p>"&gt;</p>'
);
});
async test(assert) { test("updating the value refreshes the preview", async function (assert) {
assert.strictEqual( this.set("value", "evil trout");
queryAll(".d-editor-preview").html().trim(),
"<p>evil trout</p>"
);
this.set("value", "zogstrip"); await render(hbs`<DEditor @value={{this.value}} />`);
await settled();
assert.strictEqual( assert.strictEqual(
queryAll(".d-editor-preview").html().trim(), query(".d-editor-preview").innerHTML.trim(),
"<p>zogstrip</p>" "<p>evil trout</p>"
); );
},
this.set("value", "zogstrip");
await settled();
assert.strictEqual(
query(".d-editor-preview").innerHTML.trim(),
"<p>zogstrip</p>"
);
}); });
function jumpEnd(textarea) { function jumpEnd(textarea) {
@ -93,30 +85,26 @@ discourseModule("Integration | Component | d-editor", function (hooks) {
} }
function testCase(title, testFunc) { function testCase(title, testFunc) {
componentTest(title, { chromeTest(title, async function (assert) {
template: hbs`{{d-editor value=value}}`, this.set("value", "hello world.");
beforeEach() {
this.set("value", "hello world."); await render(hbs`<DEditor @value={{this.value}} />`);
},
async test(assert) { const textarea = jumpEnd(query("textarea.d-editor-input"));
const textarea = jumpEnd(query("textarea.d-editor-input")); await testFunc.call(this, assert, textarea);
await testFunc.call(this, assert, textarea);
},
skip: !navigator.userAgent.includes("Chrome"),
}); });
} }
function composerTestCase(title, testFunc) { function composerTestCase(title, testFunc) {
componentTest(title, { test(title, async function (assert) {
template: hbs`{{d-editor value=value composerEvents=true}}`, this.set("value", "hello world.");
beforeEach() {
this.set("value", "hello world.");
},
async test(assert) { await render(
const textarea = jumpEnd(query("textarea.d-editor-input")); hbs`<DEditor @value={{this.value}} @composerEvents={{true}} />`
await testFunc.call(this, assert, textarea); );
},
const textarea = jumpEnd(query("textarea.d-editor-input"));
await testFunc.call(this, assert, textarea);
}); });
} }
@ -255,283 +243,271 @@ discourseModule("Integration | Component | d-editor", function (hooks) {
} }
); );
componentTest("advanced code", { test("advanced code", async function (assert) {
template: hbs`{{d-editor value=value}}`, this.siteSettings.code_formatting_style = "4-spaces-indent";
beforeEach() { this.set(
this.siteSettings.code_formatting_style = "4-spaces-indent"; "value",
this.set( `
"value", function xyz(x, y, z) {
` if (y === z) {
function xyz(x, y, z) { return true;
if (y === z) {
return true;
}
} }
` }
); `
}, );
async test(assert) { await render(hbs`<DEditor @value={{this.value}} />`);
const textarea = query("textarea.d-editor-input");
textarea.selectionStart = 0;
textarea.selectionEnd = textarea.value.length;
await click("button.code"); const textarea = query("textarea.d-editor-input");
assert.strictEqual( textarea.selectionStart = 0;
this.value, textarea.selectionEnd = textarea.value.length;
`
function xyz(x, y, z) { await click("button.code");
if (y === z) { assert.strictEqual(
return true; this.value,
} `
function xyz(x, y, z) {
if (y === z) {
return true;
} }
` }
); `
}, );
}); });
componentTest("code button", { test("code button", async function (assert) {
template: hbs`{{d-editor value=value}}`, this.siteSettings.code_formatting_style = "4-spaces-indent";
beforeEach() {
this.siteSettings.code_formatting_style = "4-spaces-indent";
},
async test(assert) { await render(hbs`<DEditor @value={{this.value}} />`);
const textarea = jumpEnd(query("textarea.d-editor-input"));
await click("button.code"); const textarea = jumpEnd(query("textarea.d-editor-input"));
assert.strictEqual(this.value, ` ${I18n.t("composer.code_text")}`);
this.set("value", "first line\n\nsecond line\n\nthird line"); await click("button.code");
assert.strictEqual(this.value, ` ${I18n.t("composer.code_text")}`);
textarea.selectionStart = 11; this.set("value", "first line\n\nsecond line\n\nthird line");
textarea.selectionEnd = 11;
await click("button.code"); textarea.selectionStart = 11;
assert.strictEqual( textarea.selectionEnd = 11;
this.value,
`first line await click("button.code");
assert.strictEqual(
this.value,
`first line
${I18n.t("composer.code_text")} ${I18n.t("composer.code_text")}
second line second line
third line` third line`
); );
this.set("value", "first line\n\nsecond line\n\nthird line"); this.set("value", "first line\n\nsecond line\n\nthird line");
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`first line `first line
second line second line
third line\`${I18n.t("composer.code_title")}\`` third line\`${I18n.t("composer.code_title")}\``
); );
this.set("value", "first line\n\nsecond line\n\nthird line"); this.set("value", "first line\n\nsecond line\n\nthird line");
textarea.selectionStart = 5; textarea.selectionStart = 5;
textarea.selectionEnd = 5; textarea.selectionEnd = 5;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`first\`${I18n.t("composer.code_title")}\` line `first\`${I18n.t("composer.code_title")}\` line
second line second line
third line` third line`
); );
this.set("value", "first line\n\nsecond line\n\nthird line"); this.set("value", "first line\n\nsecond line\n\nthird line");
textarea.selectionStart = 6; textarea.selectionStart = 6;
textarea.selectionEnd = 10; textarea.selectionEnd = 10;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(this.value, "first `line`\n\nsecond line\n\nthird line");
this.value, assert.strictEqual(textarea.selectionStart, 7);
"first `line`\n\nsecond line\n\nthird line" assert.strictEqual(textarea.selectionEnd, 11);
);
assert.strictEqual(textarea.selectionStart, 7);
assert.strictEqual(textarea.selectionEnd, 11);
await click("button.code"); await click("button.code");
assert.strictEqual(this.value, "first line\n\nsecond line\n\nthird line"); assert.strictEqual(this.value, "first line\n\nsecond line\n\nthird line");
assert.strictEqual(textarea.selectionStart, 6); assert.strictEqual(textarea.selectionStart, 6);
assert.strictEqual(textarea.selectionEnd, 10); assert.strictEqual(textarea.selectionEnd, 10);
textarea.selectionStart = 0; textarea.selectionStart = 0;
textarea.selectionEnd = 23; textarea.selectionEnd = 23;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
" first line\n\n second line\n\nthird line" " first line\n\n second line\n\nthird line"
); );
assert.strictEqual(textarea.selectionStart, 0); assert.strictEqual(textarea.selectionStart, 0);
assert.strictEqual(textarea.selectionEnd, 31); assert.strictEqual(textarea.selectionEnd, 31);
await click("button.code"); await click("button.code");
assert.strictEqual(this.value, "first line\n\nsecond line\n\nthird line"); assert.strictEqual(this.value, "first line\n\nsecond line\n\nthird line");
assert.strictEqual(textarea.selectionStart, 0); assert.strictEqual(textarea.selectionStart, 0);
assert.strictEqual(textarea.selectionEnd, 23); assert.strictEqual(textarea.selectionEnd, 23);
},
}); });
componentTest("code fences", { test("code fences", async function (assert) {
template: hbs`{{d-editor value=value}}`, this.set("value", "");
beforeEach() {
this.set("value", "");
},
async test(assert) { await render(hbs`<DEditor @value={{this.value}} />`);
const textarea = jumpEnd(query("textarea.d-editor-input"));
await click("button.code"); const textarea = jumpEnd(query("textarea.d-editor-input"));
assert.strictEqual(
this.value, await click("button.code");
`\`\`\` assert.strictEqual(
this.value,
`\`\`\`
${I18n.t("composer.paste_code_text")} ${I18n.t("composer.paste_code_text")}
\`\`\`` \`\`\``
); );
assert.strictEqual(textarea.selectionStart, 4); assert.strictEqual(textarea.selectionStart, 4);
assert.strictEqual(textarea.selectionEnd, 27); assert.strictEqual(textarea.selectionEnd, 27);
this.set("value", "first line\nsecond line\nthird line"); this.set("value", "first line\nsecond line\nthird line");
textarea.selectionStart = 0; textarea.selectionStart = 0;
textarea.selectionEnd = textarea.value.length; textarea.selectionEnd = textarea.value.length;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`\`\`\` `\`\`\`
first line first line
second line second line
third line third line
\`\`\` \`\`\`
` `
); );
assert.strictEqual(textarea.selectionStart, textarea.value.length); assert.strictEqual(textarea.selectionStart, textarea.value.length);
assert.strictEqual(textarea.selectionEnd, textarea.value.length); assert.strictEqual(textarea.selectionEnd, textarea.value.length);
this.set("value", "first line\nsecond line\nthird line"); this.set("value", "first line\nsecond line\nthird line");
textarea.selectionStart = 0; textarea.selectionStart = 0;
textarea.selectionEnd = 0; textarea.selectionEnd = 0;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`\`${I18n.t("composer.code_title")}\`first line `\`${I18n.t("composer.code_title")}\`first line
second line second line
third line` third line`
); );
assert.strictEqual(textarea.selectionStart, 1); assert.strictEqual(textarea.selectionStart, 1);
assert.strictEqual( assert.strictEqual(
textarea.selectionEnd, textarea.selectionEnd,
I18n.t("composer.code_title").length + 1 I18n.t("composer.code_title").length + 1
); );
this.set("value", "first line\nsecond line\nthird line"); this.set("value", "first line\nsecond line\nthird line");
textarea.selectionStart = 0; textarea.selectionStart = 0;
textarea.selectionEnd = 10; textarea.selectionEnd = 10;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`\`first line\` `\`first line\`
second line second line
third line` third line`
); );
assert.strictEqual(textarea.selectionStart, 1); assert.strictEqual(textarea.selectionStart, 1);
assert.strictEqual(textarea.selectionEnd, 11); assert.strictEqual(textarea.selectionEnd, 11);
this.set("value", "first line\nsecond line\nthird line"); this.set("value", "first line\nsecond line\nthird line");
textarea.selectionStart = 0; textarea.selectionStart = 0;
textarea.selectionEnd = 23; textarea.selectionEnd = 23;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`\`\`\` `\`\`\`
first line first line
second line second line
\`\`\` \`\`\`
third line` third line`
); );
assert.strictEqual(textarea.selectionStart, 30); assert.strictEqual(textarea.selectionStart, 30);
assert.strictEqual(textarea.selectionEnd, 30); assert.strictEqual(textarea.selectionEnd, 30);
this.set("value", "first line\nsecond line\nthird line"); this.set("value", "first line\nsecond line\nthird line");
textarea.selectionStart = 6; textarea.selectionStart = 6;
textarea.selectionEnd = 17; textarea.selectionEnd = 17;
await click("button.code"); await click("button.code");
assert.strictEqual( assert.strictEqual(
this.value, this.value,
`first \n\`\`\`\nline\nsecond\n\`\`\`\n line\nthird line` `first \n\`\`\`\nline\nsecond\n\`\`\`\n line\nthird line`
); );
assert.strictEqual(textarea.selectionStart, 27); assert.strictEqual(textarea.selectionStart, 27);
assert.strictEqual(textarea.selectionEnd, 27); assert.strictEqual(textarea.selectionEnd, 27);
document.execCommand("undo"); document.execCommand("undo");
assert.strictEqual(this.value, "first line\nsecond line\nthird line"); assert.strictEqual(this.value, "first line\nsecond line\nthird line");
},
}); });
componentTest("quote button - empty lines", { test("quote button - empty lines", async function (assert) {
template: hbs`{{d-editor value=value composerEvents=true}}`, this.set("value", "one\n\ntwo\n\nthree");
beforeEach() {
this.set("value", "one\n\ntwo\n\nthree");
},
async test(assert) {
const textarea = jumpEnd(query("textarea.d-editor-input"));
textarea.selectionStart = 0; await render(
hbs`<DEditor @value={{this.value}} @composerEvents={{true}} />`
);
await click("button.blockquote"); const textarea = jumpEnd(query("textarea.d-editor-input"));
assert.strictEqual(this.value, "> one\n> \n> two\n> \n> three"); textarea.selectionStart = 0;
assert.strictEqual(textarea.selectionStart, 0);
assert.strictEqual(textarea.selectionEnd, 25);
await click("button.blockquote"); await click("button.blockquote");
assert.strictEqual(this.value, "one\n\ntwo\n\nthree");
}, assert.strictEqual(this.value, "> one\n> \n> two\n> \n> three");
assert.strictEqual(textarea.selectionStart, 0);
assert.strictEqual(textarea.selectionEnd, 25);
await click("button.blockquote");
assert.strictEqual(this.value, "one\n\ntwo\n\nthree");
}); });
componentTest("quote button - selecting empty lines", { test("quote button - selecting empty lines", async function (assert) {
template: hbs`{{d-editor value=value composerEvents=true}}`, this.set("value", "one\n\n\n\ntwo");
beforeEach() {
this.set("value", "one\n\n\n\ntwo");
},
async test(assert) {
const textarea = jumpEnd(query("textarea.d-editor-input"));
textarea.selectionStart = 6; await render(
textarea.selectionEnd = 10; hbs`<DEditor @value={{this.value}} @composerEvents={{true}} />`
);
await click("button.blockquote"); const textarea = jumpEnd(query("textarea.d-editor-input"));
assert.strictEqual(this.value, "one\n\n\n> \n> two");
document.execCommand("undo"); textarea.selectionStart = 6;
assert.strictEqual(this.value, "one\n\n\n\ntwo"); textarea.selectionEnd = 10;
},
await click("button.blockquote");
assert.strictEqual(this.value, "one\n\n\n> \n> two");
document.execCommand("undo");
assert.strictEqual(this.value, "one\n\n\n\ntwo");
}); });
testCase("quote button", async function (assert, textarea) { testCase("quote button", async function (assert, textarea) {
@ -652,33 +628,29 @@ third line`
assert.strictEqual(textarea.selectionEnd, 18); assert.strictEqual(textarea.selectionEnd, 18);
}); });
componentTest("clicking the toggle-direction changes dir from ltr to rtl", { test("clicking the toggle-direction changes dir from ltr to rtl", async function (assert) {
template: hbs`{{d-editor value=value}}`, this.siteSettings.support_mixed_text_direction = true;
beforeEach() { this.siteSettings.default_locale = "en";
this.siteSettings.support_mixed_text_direction = true;
this.siteSettings.default_locale = "en";
},
async test(assert) { await render(hbs`<DEditor @value={{this.value}} />`);
const textarea = queryAll("textarea.d-editor-input");
await click("button.toggle-direction"); await click("button.toggle-direction");
assert.strictEqual(textarea.attr("dir"), "rtl"); assert.strictEqual(
}, query("textarea.d-editor-input").getAttribute("dir"),
"rtl"
);
}); });
componentTest("clicking the toggle-direction changes dir from ltr to rtl", { test("clicking the toggle-direction changes dir from ltr to rtl", async function (assert) {
template: hbs`{{d-editor value=value}}`, this.siteSettings.support_mixed_text_direction = true;
beforeEach() { this.siteSettings.default_locale = "en";
this.siteSettings.support_mixed_text_direction = true;
this.siteSettings.default_locale = "en";
},
async test(assert) { await render(hbs`<DEditor @value={{this.value}} />`);
const textarea = queryAll("textarea.d-editor-input");
textarea.attr("dir", "ltr"); const textarea = query("textarea.d-editor-input");
await click("button.toggle-direction"); textarea.setAttribute("dir", "ltr");
assert.strictEqual(textarea.attr("dir"), "rtl"); await click("button.toggle-direction");
}, assert.strictEqual(textarea.getAttribute("dir"), "rtl");
}); });
testCase( testCase(
@ -699,54 +671,47 @@ third line`
} }
); );
componentTest("emoji", { test("emoji", async function (assert) {
template: hbs`{{d-editor value=value}}`, // Test adding a custom button
beforeEach() { withPluginApi("0.1", (api) => {
// Test adding a custom button api.onToolbarCreate((toolbar) => {
withPluginApi("0.1", (api) => { toolbar.addButton({
api.onToolbarCreate((toolbar) => { id: "emoji",
toolbar.addButton({ group: "extras",
id: "emoji", icon: "far-smile",
group: "extras", action: () => toolbar.context.send("emoji"),
icon: "far-smile",
action: () => toolbar.context.send("emoji"),
});
}); });
}); });
this.set("value", "hello world."); });
}, this.set("value", "hello world.");
afterEach() { await render(hbs`<DEditor @value={{this.value}} />`);
clearToolbarCallbacks();
},
async test(assert) { jumpEnd(query("textarea.d-editor-input"));
jumpEnd(query("textarea.d-editor-input")); await click("button.emoji");
await click("button.emoji");
await click( await click(
'.emoji-picker .section[data-section="smileys_&_emotion"] img.emoji[title="grinning"]' '.emoji-picker .section[data-section="smileys_&_emotion"] img.emoji[title="grinning"]'
); );
assert.strictEqual( assert.strictEqual(
this.value, this.value,
"hello world. :grinning:", "hello world. :grinning:",
"it works when there is no partial emoji" "it works when there is no partial emoji"
); );
await click("textarea.d-editor-input"); await click("textarea.d-editor-input");
await fillIn(".d-editor-input", "starting to type an emoji like :gri"); await fillIn(".d-editor-input", "starting to type an emoji like :gri");
jumpEnd(query("textarea.d-editor-input")); jumpEnd(query("textarea.d-editor-input"));
await click("button.emoji"); await click("button.emoji");
await click( await click(
'.emoji-picker .section[data-section="smileys_&_emotion"] img.emoji[title="grinning"]' '.emoji-picker .section[data-section="smileys_&_emotion"] img.emoji[title="grinning"]'
); );
assert.strictEqual( assert.strictEqual(
this.value, this.value,
"starting to type an emoji like :grinning:", "starting to type an emoji like :grinning:",
"it works when there is a partial emoji" "it works when there is a partial emoji"
); );
},
}); });
testCase("replace-text event by default", async function (assert) { testCase("replace-text event by default", async function (assert) {
@ -863,35 +828,33 @@ third line`
} }
); );
componentTest("paste table", { test("paste table", async function (assert) {
template: hbs`{{d-editor value=value composerEvents=true}}`, this.set("value", "");
beforeEach() { this.siteSettings.enable_rich_text_paste = true;
this.set("value", "");
this.siteSettings.enable_rich_text_paste = true;
},
async test(assert) { await render(
let element = query(".d-editor"); hbs`<DEditor @value={{this.value}} @composerEvents={{true}} />`
await paste(element, "\ta\tb\n1\t2\t3"); );
assert.strictEqual(this.value, "||a|b|\n|---|---|---|\n|1|2|3|\n");
document.execCommand("undo"); let element = query(".d-editor");
assert.strictEqual(this.value, ""); await paste(element, "\ta\tb\n1\t2\t3");
}, assert.strictEqual(this.value, "||a|b|\n|---|---|---|\n|1|2|3|\n");
document.execCommand("undo");
assert.strictEqual(this.value, "");
}); });
componentTest("paste a different table", { test("paste a different table", async function (assert) {
template: hbs`{{d-editor value=value composerEvents=true}}`, this.set("value", "");
beforeEach() { this.siteSettings.enable_rich_text_paste = true;
this.set("value", "");
this.siteSettings.enable_rich_text_paste = true;
},
async test(assert) { await render(
let element = query(".d-editor"); hbs`<DEditor @value={{this.value}} @composerEvents={{true}} />`
await paste(element, '\ta\tb\n1\t"2\n2.5"\t3'); );
assert.strictEqual(this.value, "||a|b|\n|---|---|---|\n|1|2<br>2.5|3|\n");
}, let element = query(".d-editor");
await paste(element, '\ta\tb\n1\t"2\n2.5"\t3');
assert.strictEqual(this.value, "||a|b|\n|---|---|---|\n|1|2<br>2.5|3|\n");
}); });
testCase( testCase(
@ -1066,7 +1029,7 @@ third line`
await focus(textarea); await focus(textarea);
assert.ok(textarea.value === BEFORE); assert.strictEqual(textarea.value, BEFORE);
const [start, len] = CASE.before; const [start, len] = CASE.before;
setTextareaSelection(textarea, start, start + len); setTextareaSelection(textarea, start, start + len);

View File

@ -0,0 +1,29 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | d-icon helper", function (hooks) {
setupRenderingTest(hooks);
test("default", async function (assert) {
await render(hbs`<div class="test">{{d-icon "bars"}}</div>`);
const html = query(".test").innerHTML.trim();
assert.strictEqual(
html,
'<svg class="fa d-icon d-icon-bars svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#bars"></use></svg>'
);
});
test("with replacement", async function (assert) {
await render(hbs`<div class="test">{{d-icon "d-watching"}}</div>`);
const html = query(".test").innerHTML.trim();
assert.strictEqual(
html,
'<svg class="fa d-icon d-icon-d-watching svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#discourse-bell-exclamation"></use></svg>'
);
});
});

View File

@ -1,36 +0,0 @@
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import {
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | d-icon", function (hooks) {
setupRenderingTest(hooks);
componentTest("default", {
template: hbs`<div class="test">{{d-icon "bars"}}</div>`,
test(assert) {
const html = queryAll(".test").html().trim();
assert.strictEqual(
html,
'<svg class="fa d-icon d-icon-bars svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#bars"></use></svg>'
);
},
});
componentTest("with replacement", {
template: hbs`<div class="test">{{d-icon "d-watching"}}</div>`,
test(assert) {
const html = queryAll(".test").html().trim();
assert.strictEqual(
html,
'<svg class="fa d-icon d-icon-d-watching svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#discourse-bell-exclamation"></use></svg>'
);
},
});
});

View File

@ -1,11 +1,10 @@
import { click } from "@ember/test-helpers"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { click, render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test"; import { count, query } from "discourse/tests/helpers/qunit-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | d-navigation", function (hooks) { module("Integration | Component | d-navigation", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
@ -13,31 +12,25 @@ discourseModule("Integration | Component | d-navigation", function (hooks) {
.filter((category) => !category.parent_category_id) .filter((category) => !category.parent_category_id)
.slice(0, 4); .slice(0, 4);
this.site.setProperties({ categories }); this.site.setProperties({ categories });
this.currentUser.set( this.currentUser.set(
"indirectly_muted_category_ids", "indirectly_muted_category_ids",
categories.slice(0, 3).map((category) => category.id) categories.slice(0, 3).map((category) => category.id)
); );
}); });
componentTest("filters indirectly muted categories", { test("filters indirectly muted categories", async function (assert) {
template: hbs` await render(hbs`<DNavigation @filterType="categories" />`);
{{d-navigation await click(".category-drop .select-kit-header-wrapper");
filterType="categories"
}}
`,
async test(assert) { assert.strictEqual(
await click(".category-drop .select-kit-header-wrapper"); count(".category-row"),
1,
assert.strictEqual( "displays only categories that are not muted"
document.querySelectorAll(".category-row").length, );
1, assert.strictEqual(
"displays only categories that are not muted" query(".category-row .badge-category span").textContent.trim(),
); "dev"
assert.strictEqual( );
query(".category-row .badge-category span").textContent.trim(),
"dev"
);
},
}); });
}); });

View File

@ -1,102 +1,102 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render, triggerKeyEvent } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { showPopover } from "discourse/lib/d-popover"; import { showPopover } from "discourse/lib/d-popover";
import { click, triggerKeyEvent } from "@ember/test-helpers";
discourseModule("Integration | Component | d-popover", function (hooks) { module("Integration | Component | d-popover", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("show/hide popover from lib", { test("show/hide popover from lib", async function (assert) {
template: hbs`{{d-button translatedLabel="test" action=onButtonClick forwardEvent=true}}`, this.set("onButtonClick", (_, event) => {
showPopover(event, { content: "test", trigger: "click", duration: 0 });
});
beforeEach() { await render(hbs`
this.set("onButtonClick", (_, event) => { <DButton
showPopover(event, { content: "test", trigger: "click", duration: 0 }); @translatedLabel="test"
}); @action={{this.onButtonClick}}
}, @forwardEvent={{true}}
/>
`);
async test(assert) { assert.notOk(document.querySelector("div[data-tippy-root]"));
assert.notOk(document.querySelector("div[data-tippy-root]"));
await click(".btn"); await click(".btn");
assert.strictEqual(
document.querySelector("div[data-tippy-root]").innerText.trim(),
"test"
);
assert.equal( await click(".btn");
document.querySelector("div[data-tippy-root]").innerText.trim(), assert.notOk(document.querySelector("div[data-tippy-root]"));
"test"
);
await click(".btn");
assert.notOk(document.querySelector("div[data-tippy-root]"));
},
}); });
componentTest("show/hide popover from component", { test("show/hide popover from component", async function (assert) {
template: hbs`{{#d-popover}}{{d-button class="trigger" icon="chevron-down"}}<ul><li class="test">foo</li><li>{{d-button icon="times" class="closer"}}</li></ul>{{/d-popover}}`, await render(hbs`
<DPopover>
<DButton class="trigger" @icon="chevron-down" />
<ul>
<li class="test">foo</li>
<li><DButton class="closer" @icon="times" /></li>
</ul>
</DPopover>
`);
async test(assert) { assert.notOk(exists(".d-popover.is-expanded"));
assert.notOk(exists(".d-popover.is-expanded")); assert.notOk(exists(".test"));
assert.notOk(exists(".test"));
await click(".trigger"); await click(".trigger");
assert.ok(exists(".d-popover.is-expanded")); assert.ok(exists(".d-popover.is-expanded"));
assert.equal(query(".test").innerText.trim(), "foo"); assert.strictEqual(query(".test").innerText.trim(), "foo");
await click(".closer"); await click(".closer");
assert.notOk(exists(".d-popover.is-expanded"));
assert.notOk(exists(".d-popover.is-expanded"));
},
}); });
componentTest("using options with component", { test("using options with component", async function (assert) {
template: hbs`{{#d-popover options=(hash content="bar")}}{{d-button icon="chevron-down"}}{{/d-popover}}`, await render(hbs`
<DPopover @options={{hash content="bar"}}>
<DButton @icon="chevron-down" />
</DPopover>
`);
async test(assert) { await click(".btn");
await click(".btn"); assert.strictEqual(query(".tippy-content").innerText.trim(), "bar");
assert.equal(query(".tippy-content").innerText.trim(), "bar");
},
}); });
componentTest("d-popover component accepts a block", { test("d-popover component accepts a block", async function (assert) {
template: hbs`{{#d-popover as |state|}}{{d-button icon=(if state.isExpanded "chevron-up" "chevron-down")}}{{/d-popover}}`, await render(hbs`
<DPopover as |state|>
<DButton @icon={{if state.isExpanded "chevron-up" "chevron-down"}} />
</DPopover>
`);
async test(assert) { assert.ok(exists(".d-icon-chevron-down"));
assert.ok(exists(".d-icon-chevron-down"));
await click(".btn"); await click(".btn");
assert.ok(exists(".d-icon-chevron-up"));
assert.ok(exists(".d-icon-chevron-up"));
},
}); });
componentTest("d-popover component accepts a class property", { test("d-popover component accepts a class property", async function (assert) {
template: hbs`{{#d-popover class="foo"}}{{/d-popover}}`, await render(hbs`<DPopover @class="foo"></DPopover>`);
async test(assert) { assert.ok(exists(".d-popover.foo"));
assert.ok(exists(".d-popover.foo"));
},
}); });
componentTest("d-popover component closes on escape key", { test("d-popover component closes on escape key", async function (assert) {
template: hbs`{{#d-popover as |state|}}{{d-button icon=(if state.isExpanded "chevron-up" "chevron-down")}}{{/d-popover}}`, await render(hbs`
<DPopover as |state|>
<DButton @icon={{if state.isExpanded "chevron-up" "chevron-down"}} />
</DPopover>
`);
async test(assert) { await click(".btn");
await click(".btn"); assert.ok(exists(".d-popover.is-expanded"));
assert.ok(exists(".d-popover.is-expanded")); await triggerKeyEvent(document, "keydown", 27);
assert.notOk(exists(".d-popover.is-expanded"));
await triggerKeyEvent(document, "keydown", 27);
assert.notOk(exists(".d-popover.is-expanded"));
},
}); });
}); });

View File

@ -1,7 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
function dateInput() { function dateInput() {
@ -16,50 +16,42 @@ function noop() {}
const DEFAULT_DATE = moment("2019-01-29"); const DEFAULT_DATE = moment("2019-01-29");
discourseModule("Integration | Component | date-input", function (hooks) { module("Integration | Component | date-input", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("default", { test("default", async function (assert) {
template: hbs`{{date-input date=date}}`, this.setProperties({ date: DEFAULT_DATE });
beforeEach() { await render(hbs`<DateInput @date={{this.date}} />`);
this.setProperties({ date: DEFAULT_DATE });
},
test(assert) { assert.strictEqual(dateInput().value, "2019-01-29");
assert.strictEqual(dateInput().value, "2019-01-29");
},
}); });
componentTest("prevents mutations", { test("prevents mutations", async function (assert) {
template: hbs`{{date-input date=date onChange=onChange}}`, this.setProperties({ date: DEFAULT_DATE });
this.set("onChange", noop);
beforeEach() { await render(
this.setProperties({ date: DEFAULT_DATE }); hbs`<DateInput @date={{this.date}} @onChange={{this.onChange}} />`
this.set("onChange", noop); );
},
async test(assert) { dateInput().value = "2019-01-02";
dateInput().value = "2019-01-02"; dateInput().dispatchEvent(new Event("change"));
dateInput().dispatchEvent(new Event("change"));
assert.ok(this.date.isSame(DEFAULT_DATE)); assert.ok(this.date.isSame(DEFAULT_DATE));
},
}); });
componentTest("allows mutations through actions", { test("allows mutations through actions", async function (assert) {
template: hbs`{{date-input date=date onChange=onChange}}`, this.setProperties({ date: DEFAULT_DATE });
this.set("onChange", setDate);
beforeEach() { await render(
this.setProperties({ date: DEFAULT_DATE }); hbs`<DateInput @date={{this.date}} @onChange={{this.onChange}} />`
this.set("onChange", setDate); );
},
async test(assert) { dateInput().value = "2019-02-02";
dateInput().value = "2019-02-02"; dateInput().dispatchEvent(new Event("change"));
dateInput().dispatchEvent(new Event("change"));
assert.ok(this.date.isSame(moment("2019-02-02"))); assert.ok(this.date.isSame(moment("2019-02-02")));
},
}); });
}); });

View File

@ -1,7 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
function fromDateInput() { function fromDateInput() {
@ -22,24 +22,19 @@ function toTimeInput() {
const DEFAULT_DATE_TIME = moment("2019-01-29 14:45"); const DEFAULT_DATE_TIME = moment("2019-01-29 14:45");
discourseModule( module("Integration | Component | date-time-input-range", function (hooks) {
"Integration | Component | date-time-input-range", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("default", { test("default", async function (assert) {
template: hbs`{{date-time-input-range from=from to=to}}`, this.setProperties({ from: DEFAULT_DATE_TIME, to: null });
beforeEach() { await render(
this.setProperties({ from: DEFAULT_DATE_TIME, to: null }); hbs`<DateTimeInputRange @from={{this.from}} @to={{this.to}} />`
}, );
test(assert) { assert.strictEqual(fromDateInput().value, "2019-01-29");
assert.strictEqual(fromDateInput().value, "2019-01-29"); assert.strictEqual(fromTimeInput().dataset.name, "14:45");
assert.strictEqual(fromTimeInput().dataset.name, "14:45"); assert.strictEqual(toDateInput().value, "");
assert.strictEqual(toDateInput().value, ""); assert.strictEqual(toTimeInput().dataset.name, "--:--");
assert.strictEqual(toTimeInput().dataset.name, "--:--"); });
}, });
});
}
);

View File

@ -1,11 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
function dateInput() { function dateInput() {
@ -22,61 +18,49 @@ function setDate(date) {
const DEFAULT_DATE_TIME = moment("2019-01-29 14:45"); const DEFAULT_DATE_TIME = moment("2019-01-29 14:45");
discourseModule("Integration | Component | date-time-input", function (hooks) { module("Integration | Component | date-time-input", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("default", { test("default", async function (assert) {
template: hbs`{{date-time-input date=date}}`, this.setProperties({ date: DEFAULT_DATE_TIME });
beforeEach() { await render(hbs`<DateTimeInput @date={{this.date}} />`);
this.setProperties({ date: DEFAULT_DATE_TIME });
},
test(assert) { assert.strictEqual(dateInput().value, "2019-01-29");
assert.strictEqual(dateInput().value, "2019-01-29"); assert.strictEqual(timeInput().dataset.name, "14:45");
assert.strictEqual(timeInput().dataset.name, "14:45");
},
}); });
componentTest("prevents mutations", { test("prevents mutations", async function (assert) {
template: hbs`{{date-time-input date=date}}`, this.setProperties({ date: DEFAULT_DATE_TIME });
beforeEach() { await render(hbs`<DateTimeInput @date={{this.date}} />`);
this.setProperties({ date: DEFAULT_DATE_TIME });
},
async test(assert) { dateInput().value = "2019-01-02";
dateInput().value = "2019-01-02";
assert.ok(this.date.isSame(DEFAULT_DATE_TIME)); assert.ok(this.date.isSame(DEFAULT_DATE_TIME));
},
}); });
componentTest("allows mutations through actions", { test("allows mutations through actions", async function (assert) {
template: hbs`{{date-time-input date=date onChange=onChange}}`, this.setProperties({ date: DEFAULT_DATE_TIME });
this.set("onChange", setDate);
beforeEach() { await render(
this.setProperties({ date: DEFAULT_DATE_TIME }); hbs`<DateTimeInput @date={{this.date}} @onChange={{this.onChange}} />`
this.set("onChange", setDate); );
},
async test(assert) { dateInput().value = "2019-01-02";
dateInput().value = "2019-01-02"; dateInput().dispatchEvent(new Event("change"));
dateInput().dispatchEvent(new Event("change"));
assert.ok(this.date.isSame(moment("2019-01-02 14:45"))); assert.ok(this.date.isSame(moment("2019-01-02 14:45")));
},
}); });
componentTest("can hide time", { test("can hide time", async function (assert) {
template: hbs`{{date-time-input date=date showTime=false}}`, this.setProperties({ date: DEFAULT_DATE_TIME });
beforeEach() { await render(
this.setProperties({ date: DEFAULT_DATE_TIME }); hbs`<DateTimeInput @date={{this.date}} @showTime={{false}} />`
}, );
async test(assert) { assert.notOk(exists(timeInput()));
assert.notOk(exists(timeInput()));
},
}); });
}); });

View File

@ -1,52 +1,43 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { click } from "@ember/test-helpers";
discourseModule("Integration | Component | emoji-picker", function (hooks) { module("Integration | Component | emoji-picker", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("when placement == bottom, places the picker on the bottom", { test("when placement == bottom, places the picker on the bottom", async function (assert) {
template: hbs` this.set("showEmojiPicker", () => {
{{d-button class="emoji-picker-anchor" action=showEmojiPicker}} this.set("pickerIsActive", true);
{{emoji-picker isActive=pickerIsActive placement="bottom"}} });
`,
beforeEach() { await render(hbs`
this.set("showEmojiPicker", () => { <DButton class="emoji-picker-anchor" @action={{this.showEmojiPicker}} />
this.set("pickerIsActive", true); <EmojiPicker @isActive={{this.pickerIsActive}} @placement="bottom" />
}); `);
},
async test(assert) { await click(".emoji-picker-anchor");
await click(".emoji-picker-anchor"); assert.strictEqual(
assert.equal( query(".emoji-picker.opened").getAttribute("data-popper-placement"),
query(".emoji-picker.opened").getAttribute("data-popper-placement"), "bottom"
"bottom" );
);
},
}); });
componentTest("when placement == right, places the picker on the right", { test("when placement == right, places the picker on the right", async function (assert) {
template: hbs` this.set("showEmojiPicker", () => {
{{d-button class="emoji-picker-anchor" action=showEmojiPicker}} this.set("pickerIsActive", true);
{{emoji-picker isActive=pickerIsActive placement="right"}} });
`,
beforeEach() { await render(hbs`
this.set("showEmojiPicker", () => { <DButton class="emoji-picker-anchor" @action={{this.showEmojiPicker}} />
this.set("pickerIsActive", true); <EmojiPicker @isActive={{this.pickerIsActive}} @placement="right" />
}); `);
},
async test(assert) { await click(".emoji-picker-anchor");
await click(".emoji-picker-anchor"); assert.strictEqual(
assert.equal( query(".emoji-picker.opened").getAttribute("data-popper-placement"),
query(".emoji-picker.opened").getAttribute("data-popper-placement"), "right"
"right" );
);
},
}); });
}); });

View File

@ -1,26 +1,16 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { fillIn, render } from "@ember/test-helpers";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import { createFile } from "discourse/tests/helpers/qunit-helpers";
import {
createFile,
discourseModule,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender, { response } from "discourse/tests/helpers/create-pretender"; import pretender, { response } from "discourse/tests/helpers/create-pretender";
import { fillIn } from "@ember/test-helpers"; import selectKit from "discourse/tests/helpers/select-kit-helper";
let requestNumber; let requestNumber;
discourseModule("Integration | Component | emoji-uploader", function (hooks) { module("Integration | Component | emoji-uploader", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
const template = hbs` {{emoji-uploader
emojiGroups=emojiGroups
done=doneUpload
id="emoji-uploader"
}}`;
hooks.beforeEach(function () { hooks.beforeEach(function () {
requestNumber = 0; requestNumber = 0;
this.setProperties({ this.setProperties({
@ -46,84 +36,93 @@ discourseModule("Integration | Component | emoji-uploader", function (hooks) {
}); });
}); });
componentTest("uses the selected group for the upload", { test("uses the selected group for the upload", async function (assert) {
template, await render(hbs`
<EmojiUploader
@id="emoji-uploader"
@emojiGroups={{this.emojiGroups}}
@done={{this.doneUpload}}
/>
`);
async test(assert) { const done = assert.async();
const done = assert.async(); await selectKit("#emoji-group-selector").expand();
await selectKit("#emoji-group-selector").expand(); await selectKit("#emoji-group-selector").selectRowByValue("cool-emojis");
await selectKit("#emoji-group-selector").selectRowByValue("cool-emojis");
this.set("doneUpload", (upload, group) => { this.set("doneUpload", (upload, group) => {
assert.strictEqual("cool-emojis", group); assert.strictEqual("cool-emojis", group);
done();
});
const image = createFile("avatar.png");
await this.container
.lookup("service:app-events")
.trigger("upload-mixin:emoji-uploader:add-files", image);
});
test("does not clear the selected group between multiple uploads", async function (assert) {
await render(hbs`
<EmojiUploader
@id="emoji-uploader"
@emojiGroups={{this.emojiGroups}}
@done={{this.doneUpload}}
/>
`);
const done = assert.async();
await selectKit("#emoji-group-selector").expand();
await selectKit("#emoji-group-selector").selectRowByValue("cool-emojis");
let uploadDoneCount = 0;
this.set("doneUpload", (upload, group) => {
uploadDoneCount++;
assert.strictEqual("cool-emojis", group);
if (uploadDoneCount === 2) {
done(); done();
}); }
const image = createFile("avatar.png"); });
await this.container
.lookup("service:app-events") const image = createFile("avatar.png");
.trigger("upload-mixin:emoji-uploader:add-files", image); const image2 = createFile("avatar2.png");
},
await this.container
.lookup("service:app-events")
.trigger("upload-mixin:emoji-uploader:add-files", [image, image2]);
}); });
componentTest("does not clear the selected group between multiple uploads", { test("clears the name after the first upload to avoid duplicate names", async function (assert) {
template, await render(hbs`
<EmojiUploader
@id="emoji-uploader"
@emojiGroups={{this.emojiGroups}}
@done={{this.doneUpload}}
/>
`);
async test(assert) { const done = assert.async();
const done = assert.async(); await selectKit("#emoji-group-selector").expand();
await selectKit("#emoji-group-selector").expand(); await selectKit("#emoji-group-selector").selectRowByValue("cool-emojis");
await selectKit("#emoji-group-selector").selectRowByValue("cool-emojis"); await fillIn("#emoji-name", "okay");
let uploadDoneCount = 0; let uploadDoneCount = 0;
this.set("doneUpload", (upload, group) => { this.set("doneUpload", (upload) => {
uploadDoneCount++; uploadDoneCount++;
assert.strictEqual("cool-emojis", group);
if (uploadDoneCount === 2) { if (uploadDoneCount === 1) {
done(); assert.strictEqual(upload.name, "okay");
} }
});
const image = createFile("avatar.png"); if (uploadDoneCount === 2) {
const image2 = createFile("avatar2.png"); assert.strictEqual(upload.name, null);
await this.container done();
.lookup("service:app-events") }
.trigger("upload-mixin:emoji-uploader:add-files", [image, image2]); });
},
const image = createFile("avatar.png");
const image2 = createFile("avatar2.png");
await this.container
.lookup("service:app-events")
.trigger("upload-mixin:emoji-uploader:add-files", [image, image2]);
}); });
componentTest(
"clears the name after the first upload to avoid duplicate names",
{
template,
async test(assert) {
const done = assert.async();
await selectKit("#emoji-group-selector").expand();
await selectKit("#emoji-group-selector").selectRowByValue(
"cool-emojis"
);
await fillIn("#emoji-name", "okay");
let uploadDoneCount = 0;
this.set("doneUpload", (upload) => {
uploadDoneCount++;
if (uploadDoneCount === 1) {
assert.strictEqual(upload.name, "okay");
}
if (uploadDoneCount === 2) {
assert.strictEqual(upload.name, null);
done();
}
});
const image = createFile("avatar.png");
const image2 = createFile("avatar2.png");
await this.container
.lookup("service:app-events")
.trigger("upload-mixin:emoji-uploader:add-files", [image, image2]);
},
}
);
}); });

View File

@ -1,18 +1,16 @@
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | empty-state", function (hooks) { module("Integration | Component | empty-state", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("it renders", { test("it renders", async function (assert) {
template: hbs`<EmptyState @title="title" @body="body" />`, await render(hbs`<EmptyState @title="title" @body="body" />`);
test(assert) { assert.strictEqual(query("[data-test-title]").textContent, "title");
assert.strictEqual(query("[data-test-title]").textContent, "title"); assert.strictEqual(query("[data-test-body]").textContent, "body");
assert.strictEqual(query("[data-test-body]").textContent, "body");
},
}); });
}); });

View File

@ -1,47 +1,35 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render, triggerKeyEvent } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import { click, triggerKeyEvent } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | flat-button", function (hooks) { module("Integration | Component | flat-button", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("press Enter", { test("press Enter", async function (assert) {
template: hbs`{{flat-button action=action}}`, this.set("foo", null);
this.set("action", () => {
this.set("foo", "bar");
});
beforeEach() { await render(hbs`<FlatButton @action={{this.action}} />`);
this.set("foo", null);
this.set("action", () => {
this.set("foo", "bar");
});
},
async test(assert) { await triggerKeyEvent(".btn-flat", "keydown", 32);
await triggerKeyEvent(".btn-flat", "keydown", 32); assert.strictEqual(this.foo, null);
assert.strictEqual(this.foo, null); await triggerKeyEvent(".btn-flat", "keydown", 13);
assert.strictEqual(this.foo, "bar");
await triggerKeyEvent(".btn-flat", "keydown", 13);
assert.strictEqual(this.foo, "bar");
},
}); });
componentTest("click", {
template: hbs`{{flat-button action=action}}`,
beforeEach() { test("click", async function (assert) {
this.set("foo", null); this.set("foo", null);
this.set("action", () => { this.set("action", () => {
this.set("foo", "bar"); this.set("foo", "bar");
}); });
},
async test(assert) { await render(hbs`<FlatButton @action={{this.action}} />`);
await click(".btn-flat");
assert.strictEqual(this.foo, "bar"); await click(".btn-flat");
}, assert.strictEqual(this.foo, "bar");
}); });
}); });

View File

@ -1,69 +1,60 @@
import EmberObject from "@ember/object"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import EmberObject from "@ember/object";
discourseModule( module("Integration | Component | group-list site-setting", function (hooks) {
"Integration | Component | group-list site-setting", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("default", { test("default", async function (assert) {
template: hbs`{{site-setting setting=setting}}`, this.site.groups = [
{
beforeEach() { id: 1,
this.site.groups = [ name: "Donuts",
{
id: 1,
name: "Donuts",
},
{
id: 2,
name: "Cheese cake",
},
];
this.set(
"setting",
EmberObject.create({
allowsNone: undefined,
category: "foo",
default: "",
description: "Choose groups",
overridden: false,
placeholder: null,
preview: null,
secret: false,
setting: "foo_bar",
type: "group_list",
validValues: undefined,
value: "1",
})
);
}, },
{
async test(assert) { id: 2,
const subject = selectKit(".list-setting"); name: "Cheese cake",
assert.strictEqual(
subject.header().value(),
"1",
"it selects the setting's value"
);
await subject.expand();
await subject.selectRowByValue("2");
assert.strictEqual(
subject.header().value(),
"1,2",
"it allows to select a setting from the list of choices"
);
}, },
}); ];
}
); this.set(
"setting",
EmberObject.create({
allowsNone: undefined,
category: "foo",
default: "",
description: "Choose groups",
overridden: false,
placeholder: null,
preview: null,
secret: false,
setting: "foo_bar",
type: "group_list",
validValues: undefined,
value: "1",
})
);
await render(hbs`<SiteSetting @setting={{this.setting}} />`);
const subject = selectKit(".list-setting");
assert.strictEqual(
subject.header().value(),
"1",
"it selects the setting's value"
);
await subject.expand();
await subject.selectRowByValue("2");
assert.strictEqual(
subject.header().value(),
"1,2",
"it allows to select a setting from the list of choices"
);
});
});

View File

@ -1,88 +1,72 @@
import { import { module, test } from "qunit";
count, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
discourseModule, import { render } from "@ember/test-helpers";
exists, import { count, exists } from "discourse/tests/helpers/qunit-helpers";
} from "discourse/tests/helpers/qunit-helpers";
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module("Integration | Component | group-membership-button", function (hooks) {
"Integration | Component | group-membership-button", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("canJoinGroup", { test("canJoinGroup", async function (assert) {
template: hbs`{{group-membership-button model=model}}`, this.set("model", { public_admission: false, is_group_user: true });
beforeEach() { await render(hbs`<GroupMembershipButton @model={{this.model}} />`);
this.set("model", { public_admission: false, is_group_user: true });
},
async test(assert) { assert.ok(
assert.ok( !exists(".group-index-join"),
!exists(".group-index-join"), "can't join group if public_admission is false"
"can't join group if public_admission is false" );
);
this.set("model.public_admission", true); this.set("model.public_admission", true);
assert.ok( assert.ok(
!exists(".group-index-join"), !exists(".group-index-join"),
"can't join group if user is already in the group" "can't join group if user is already in the group"
); );
this.set("model.is_group_user", false); this.set("model.is_group_user", false);
assert.ok(exists(".group-index-join"), "allowed to join group"); assert.ok(exists(".group-index-join"), "allowed to join group");
}, });
test("canLeaveGroup", async function (assert) {
this.set("model", { public_exit: false, is_group_user: false });
await render(hbs`<GroupMembershipButton @model={{this.model}} />`);
assert.ok(
!exists(".group-index-leave"),
"can't leave group if public_exit is false"
);
this.set("model.public_exit", true);
assert.ok(
!exists(".group-index-leave"),
"can't leave group if user is not in the group"
);
this.set("model.is_group_user", true);
assert.strictEqual(
count(".group-index-leave"),
1,
"allowed to leave group"
);
});
test("canRequestMembership", async function (assert) {
this.set("model", {
allow_membership_requests: true,
is_group_user: true,
}); });
componentTest("canLeaveGroup", { await render(hbs`<GroupMembershipButton @model={{this.model}} />`);
template: hbs`{{group-membership-button model=model}}`,
beforeEach() {
this.set("model", { public_exit: false, is_group_user: false });
},
async test(assert) {
assert.ok(
!exists(".group-index-leave"),
"can't leave group if public_exit is false"
);
this.set("model.public_exit", true); assert.ok(
assert.ok( !exists(".group-index-request"),
!exists(".group-index-leave"), "can't request for membership if user is already in the group"
"can't leave group if user is not in the group" );
); this.set("model.is_group_user", false);
assert.ok(
this.set("model.is_group_user", true); exists(".group-index-request"),
assert.strictEqual( "allowed to request for group membership"
count(".group-index-leave"), );
1, });
"allowed to leave group" });
);
},
});
componentTest("canRequestMembership", {
template: hbs`{{group-membership-button model=model}}`,
beforeEach() {
this.set("model", {
allow_membership_requests: true,
is_group_user: true,
});
},
async test(assert) {
assert.ok(
!exists(".group-index-request"),
"can't request for membership if user is already in the group"
);
this.set("model.is_group_user", false);
assert.ok(
exists(".group-index-request"),
"allowed to request for group membership"
);
},
});
}
);

View File

@ -1,36 +1,29 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import I18n from "I18n"; import I18n from "I18n";
import { click } from "@ember/test-helpers";
discourseModule("Integration | Component | hidden-details", function (hooks) { module("Integration | Component | hidden-details", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("Shows a link and turns link into details on click", { test("Shows a link and turns link into details on click", async function (assert) {
template: hbs`{{hidden-details label=label details=details}}`, this.set("label", "label");
this.set("details", "details");
beforeEach() { await render(
this.set("label", "label"); hbs`<HiddenDetails @label={{this.label}} @details={{this.details}} />`
this.set("details", "details"); );
},
async test(assert) { assert.ok(exists(".btn-link"));
assert.ok(exists(".btn-link")); assert.strictEqual(query(".btn-link span").innerText, I18n.t("label"));
assert.ok(query(".btn-link span").innerText === I18n.t("label")); assert.notOk(exists(".description"));
assert.notOk(exists(".description"));
await click(".btn-link"); await click(".btn-link");
assert.notOk(exists(".btn-link")); assert.notOk(exists(".btn-link"));
assert.ok(exists(".description")); assert.ok(exists(".description"));
assert.ok(query(".description").innerText === "details"); assert.strictEqual(query(".description").innerText, "details");
},
}); });
}); });

View File

@ -1,48 +1,34 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
const LONG_CODE_BLOCK = "puts a\n".repeat(15000); const LONG_CODE_BLOCK = "puts a\n".repeat(15000);
discourseModule("Integration | Component | highlighted-code", function (hooks) { module("Integration | Component | highlighted-code", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("highlighting code", { test("highlighting code", async function (assert) {
template: hbs`{{highlighted-code lang='ruby' code=code}}`, this.session.highlightJsPath =
"/assets/highlightjs/highlight-test-bundle.min.js";
this.set("code", "def test; end");
beforeEach() { await render(hbs`<HighlightedCode @lang="ruby" @code={{this.code}} />`);
this.session.highlightJsPath =
"/assets/highlightjs/highlight-test-bundle.min.js";
this.set("code", "def test; end");
},
test(assert) { assert.strictEqual(
assert.strictEqual( query("code.ruby.hljs .hljs-function .hljs-keyword").innerText.trim(),
queryAll("code.ruby.hljs .hljs-function .hljs-keyword").text().trim(), "def"
"def" );
);
},
}); });
componentTest("large code blocks are not highlighted", { test("large code blocks are not highlighted", async function (assert) {
template: hbs`{{highlighted-code lang='ruby' code=code}}`, this.session.highlightJsPath =
"/assets/highlightjs/highlight-test-bundle.min.js";
this.set("code", LONG_CODE_BLOCK);
beforeEach() { await render(hbs`<HighlightedCode @lang="ruby" @code={{this.code}} />`);
this.session.highlightJsPath =
"/assets/highlightjs/highlight-test-bundle.min.js";
this.set("code", LONG_CODE_BLOCK);
},
test(assert) { assert.strictEqual(query("code").innerText.trim(), LONG_CODE_BLOCK.trim());
assert.strictEqual(
queryAll("code").text().trim(),
LONG_CODE_BLOCK.trim()
);
},
}); });
}); });

View File

@ -1,21 +1,17 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, exists } from "discourse/tests/helpers/qunit-helpers"; import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | html-safe-helper", function (hooks) { module("Integration | Component | html-safe-helper", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("default", { test("default", async function (assert) {
template: hbs`{{html-safe string}}`, this.set("string", "<p class='cookies'>biscuits</p>");
beforeEach() { await render(hbs`{{html-safe string}}`);
this.set("string", "<p class='cookies'>biscuits</p>");
},
async test(assert) { assert.ok(exists("p.cookies"), "it displays the string as html");
assert.ok(exists("p.cookies"), "it displays the string as html");
},
}); });
}); });

View File

@ -1,33 +1,29 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { queryAll } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | iframed-html", function (hooks) { module("Integration | Component | iframed-html", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("appends the html into the iframe", { test("appends the html into the iframe", async function (assert) {
template: hbs`{{iframed-html html="<h1 id='find-me'>hello</h1>" className='this-is-an-iframe'}}`, await render(
hbs`<IframedHtml @html="<h1 id='find-me'>hello</h1>" @className="this-is-an-iframe" />`
);
async test(assert) { const iframe = queryAll("iframe.this-is-an-iframe");
const iframe = queryAll("iframe.this-is-an-iframe"); assert.strictEqual(iframe.length, 1, "inserts an iframe");
assert.strictEqual(iframe.length, 1, "inserts an iframe");
assert.ok( assert.ok(
iframe[0].classList.contains("this-is-an-iframe"), iframe[0].classList.contains("this-is-an-iframe"),
"Adds className to the iframes classList" "Adds className to the iframes classList"
); );
assert.strictEqual( assert.strictEqual(
iframe[0].contentWindow.document.body.querySelectorAll("#find-me") iframe[0].contentWindow.document.body.querySelectorAll("#find-me").length,
.length, 1,
1, "inserts the passed in html into the iframe"
"inserts the passed in html into the iframe" );
);
},
}); });
}); });

View File

@ -1,19 +1,22 @@
import componentTest, { import { module } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { chromeTest, query } from "discourse/tests/helpers/qunit-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module(
"Integration | Component | consistent input/dropdown/button sizes", "Integration | Component | consistent input/dropdown/button sizes",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("icon only button, icon and text button, text only button", { // these tests fail on Firefox 78 in CI, skipping for now
template: hbs`{{d-button icon="plus"}} {{d-button icon="plus" label="topic.create"}} {{d-button label="topic.create"}}`, chromeTest(
"icon only button, icon and text button, text only button",
async function (assert) {
await render(
hbs`<DButton @icon="plus" /> <DButton @icon="plus" @label="topic.create" /> <DButton @label="topic.create" />`
);
test(assert) {
assert.strictEqual( assert.strictEqual(
query(".btn:nth-child(1)").offsetHeight, query(".btn:nth-child(1)").offsetHeight,
query(".btn:nth-child(2)").offsetHeight, query(".btn:nth-child(2)").offsetHeight,
@ -24,37 +27,31 @@ discourseModule(
query(".btn:nth-child(3)").offsetHeight, query(".btn:nth-child(3)").offsetHeight,
"have equal height" "have equal height"
); );
}, }
// these tests fail on Firefox 78 in CI, skipping for now );
skip: !navigator.userAgent.includes("Chrome"),
chromeTest("button + text input", async function (assert) {
await render(
hbs`<TextField /> <DButton @icon="plus" @label="topic.create" />`
);
assert.strictEqual(
query("input").offsetHeight,
query(".btn").offsetHeight,
"have equal height"
);
}); });
componentTest("button + text input", { chromeTest("combo box + input", async function (assert) {
template: hbs`{{text-field}} {{d-button icon="plus" label="topic.create"}}`, await render(
hbs`<ComboBox @options={{hash none="category.none"}} /> <TextField />`
);
test(assert) { assert.strictEqual(
assert.strictEqual( query("input").offsetHeight,
query("input").offsetHeight, query(".combo-box").offsetHeight,
query(".btn").offsetHeight, "have equal height"
"have equal height" );
);
},
skip: !navigator.userAgent.includes("Chrome"),
});
componentTest("combo box + input", {
template: hbs`{{combo-box options=(hash none="category.none")}} {{text-field}}`,
test(assert) {
assert.strictEqual(
query("input").offsetHeight,
query(".combo-box").offsetHeight,
"have equal height"
);
},
skip: !navigator.userAgent.includes("Chrome"),
}); });
} }
); );

View File

@ -1,57 +1,48 @@
import { set } from "@ember/object"; import { module, test } from "qunit";
import { click } from "@ember/test-helpers"; import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import User from "discourse/models/user"; import { click, render } from "@ember/test-helpers";
import componentTest, { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import pretender from "discourse/tests/helpers/create-pretender";
import {
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import User from "discourse/models/user";
discourseModule("Integration | Component | invite-panel", function (hooks) { module("Integration | Component | invite-panel", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("shows the invite link after it is generated", { test("shows the invite link after it is generated", async function (assert) {
template: hbs`{{invite-panel panel=panel}}`, pretender.get("/u/search/users", () => {
return [200, { "Content-Type": "application/json" }, { users: [] }];
});
beforeEach() { pretender.post("/invites", () => {
pretender.get("/u/search/users", () => { return [
return [200, { "Content-Type": "application/json" }, { users: [] }]; 200,
}); { "Content-Type": "application/json" },
{
link: "http://example.com/invites/92c297e886a0ca03089a109ccd6be155",
},
];
});
pretender.post("/invites", () => { this.currentUser.set("details", { can_invite_via_email: true });
return [ this.set("panel", {
200, id: "invite",
{ "Content-Type": "application/json" }, model: { inviteModel: User.create(this.currentUser) },
{ });
link: "http://example.com/invites/92c297e886a0ca03089a109ccd6be155",
},
];
});
set(this.currentUser, "details", { can_invite_via_email: true }); await render(hbs`<InvitePanel @panel={{this.panel}} />`);
this.set("panel", {
id: "invite",
model: { inviteModel: User.create(this.currentUser) },
});
},
async test(assert) { const input = selectKit(".invite-user-input");
const input = selectKit(".invite-user-input"); await input.expand();
await input.expand(); await input.fillInFilter("eviltrout@example.com");
await input.fillInFilter("eviltrout@example.com"); await input.selectRowByValue("eviltrout@example.com");
await input.selectRowByValue("eviltrout@example.com"); assert.ok(!exists(".send-invite:disabled"));
assert.ok(!exists(".send-invite:disabled"));
await click(".generate-invite-link"); await click(".generate-invite-link");
assert.strictEqual( assert.strictEqual(
query(".invite-link-input").value, query(".invite-link-input").value,
"http://example.com/invites/92c297e886a0ca03089a109ccd6be155" "http://example.com/invites/92c297e886a0ca03089a109ccd6be155"
); );
},
}); });
}); });

View File

@ -1,34 +1,32 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { configureEyeline } from "discourse/lib/eyeline"; import { configureEyeline } from "discourse/lib/eyeline";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | load-more", function (hooks) { module("Integration | Component | load-more", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("updates once after initialization", { hooks.beforeEach(function () {
template: hbs` configureEyeline({
{{#load-more selector=".numbers tr" action=loadMore}} skipUpdate: false,
rootElement: "#ember-testing",
});
});
hooks.afterEach(function () {
configureEyeline();
});
test("updates once after initialization", async function (assert) {
this.set("loadMore", () => this.set("loadedMore", true));
await render(hbs`
<LoadMore @selector=".numbers tr" @action={{this.loadMore}}>
<table class="numbers"><tr></tr></table> <table class="numbers"><tr></tr></table>
{{/load-more}} </LoadMore>
`, `);
beforeEach() { assert.ok(this.loadedMore);
this.set("loadMore", () => this.set("loadedMore", true));
configureEyeline({
skipUpdate: false,
rootElement: "#ember-testing",
});
},
afterEach() {
configureEyeline();
},
test(assert) {
assert.ok(this.loadedMore);
},
}); });
}); });

View File

@ -1,35 +1,31 @@
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import createStore from "discourse/tests/helpers/create-store"; import createStore from "discourse/tests/helpers/create-store";
discourseModule("Integration | Component | pending-post", function (hooks) { module("Integration | Component | pending-post", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("it renders", { test("it renders", async function (assert) {
template: hbs`<PendingPost @post={{this.post}}/>`, const store = createStore();
store.createRecord("category", { id: 2 });
const post = store.createRecord("pending-post", {
id: 1,
topic_url: "topic-url",
username: "USERNAME",
category_id: 2,
raw_text: "**bold text**",
});
this.set("post", post);
beforeEach() { await render(hbs`<PendingPost @post={{this.post}}/>`);
const store = createStore();
store.createRecord("category", { id: 2 });
const post = store.createRecord("pending-post", {
id: 1,
topic_url: "topic-url",
username: "USERNAME",
category_id: 2,
raw_text: "**bold text**",
});
this.set("post", post);
},
test(assert) { assert.strictEqual(
assert.strictEqual( query("p.excerpt").textContent.trim(),
query("p.excerpt").textContent.trim(), "bold text",
"bold text", "renders the cooked text"
"renders the cooked text" );
);
},
}); });
}); });

View File

@ -1,120 +1,94 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
discourseModule( module("Integration | Component | relative-time-picker", function (hooks) {
"Integration | Component | relative-time-picker", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("prefills and preselects minutes", { test("prefills and preselects minutes", async function (assert) {
template: hbs`{{relative-time-picker durationMinutes="5"}}`, await render(hbs`<RelativeTimePicker @durationMinutes="5" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "mins");
assert.strictEqual(this.subject.header().value(), "mins"); assert.strictEqual(prefilledDuration, "5");
assert.strictEqual(prefilledDuration, "5"); });
},
});
componentTest("prefills and preselects hours based on translated minutes", { test("prefills and preselects hours based on translated minutes", async function (assert) {
template: hbs`{{relative-time-picker durationMinutes="90"}}`, await render(hbs`<RelativeTimePicker @durationMinutes="90" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "hours");
assert.strictEqual(this.subject.header().value(), "hours"); assert.strictEqual(prefilledDuration, "1.5");
assert.strictEqual(prefilledDuration, "1.5"); });
},
});
componentTest("prefills and preselects days based on translated minutes", { test("prefills and preselects days based on translated minutes", async function (assert) {
template: hbs`{{relative-time-picker durationMinutes="2880"}}`, await render(hbs`<RelativeTimePicker @durationMinutes="2880" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "days");
assert.strictEqual(this.subject.header().value(), "days"); assert.strictEqual(prefilledDuration, "2");
assert.strictEqual(prefilledDuration, "2"); });
},
});
componentTest( test("prefills and preselects months based on translated minutes", async function (assert) {
"prefills and preselects months based on translated minutes", await render(hbs`<RelativeTimePicker @durationMinutes="129600" />`);
{
template: hbs`{{relative-time-picker durationMinutes="129600"}}`,
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "months");
assert.strictEqual(this.subject.header().value(), "months"); assert.strictEqual(prefilledDuration, "3");
assert.strictEqual(prefilledDuration, "3"); });
},
}
);
componentTest("prefills and preselects years based on translated minutes", { test("prefills and preselects years based on translated minutes", async function (assert) {
template: hbs`{{relative-time-picker durationMinutes="525600"}}`, await render(hbs`<RelativeTimePicker @durationMinutes="525600" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "years");
assert.strictEqual(this.subject.header().value(), "years"); assert.strictEqual(prefilledDuration, "1");
assert.strictEqual(prefilledDuration, "1"); });
},
});
componentTest("prefills and preselects hours", { test("prefills and preselects hours", async function (assert) {
template: hbs`{{relative-time-picker durationHours="5"}}`, await render(hbs`<RelativeTimePicker @durationHours="5" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "hours");
assert.strictEqual(this.subject.header().value(), "hours"); assert.strictEqual(prefilledDuration, "5");
assert.strictEqual(prefilledDuration, "5"); });
},
});
componentTest("prefills and preselects minutes based on translated hours", { test("prefills and preselects minutes based on translated hours", async function (assert) {
template: hbs`{{relative-time-picker durationHours="0.5"}}`, await render(hbs`<RelativeTimePicker @durationHours="0.5" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "mins");
assert.strictEqual(this.subject.header().value(), "mins"); assert.strictEqual(prefilledDuration, "30");
assert.strictEqual(prefilledDuration, "30"); });
},
});
componentTest("prefills and preselects days based on translated hours", { test("prefills and preselects days based on translated hours", async function (assert) {
template: hbs`{{relative-time-picker durationHours="48"}}`, await render(hbs`<RelativeTimePicker @durationHours="48" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "days");
assert.strictEqual(this.subject.header().value(), "days"); assert.strictEqual(prefilledDuration, "2");
assert.strictEqual(prefilledDuration, "2"); });
},
});
componentTest("prefills and preselects months based on translated hours", { test("prefills and preselects months based on translated hours", async function (assert) {
template: hbs`{{relative-time-picker durationHours="2160"}}`, await render(hbs`<RelativeTimePicker @durationHours="2160" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "months");
assert.strictEqual(this.subject.header().value(), "months"); assert.strictEqual(prefilledDuration, "3");
assert.strictEqual(prefilledDuration, "3"); });
},
});
componentTest("prefills and preselects years based on translated hours", { test("prefills and preselects years based on translated hours", async function (assert) {
template: hbs`{{relative-time-picker durationHours="17520"}}`, await render(hbs`<RelativeTimePicker @durationHours="17520" />`);
test(assert) { const prefilledDuration = query(".relative-time-duration").value;
const prefilledDuration = query(".relative-time-duration").value; assert.strictEqual(this.subject.header().value(), "years");
assert.strictEqual(this.subject.header().value(), "years"); assert.strictEqual(prefilledDuration, "2");
assert.strictEqual(prefilledDuration, "2"); });
}, });
});
}
);

View File

@ -1,151 +1,130 @@
import { blur, click, fillIn } from "@ember/test-helpers"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { blur, click, fillIn, render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test"; import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
import {
count,
discourseModule,
exists,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n"; import I18n from "I18n";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module("Integration | Component | secret-value-list", function (hooks) {
"Integration | Component | secret-value-list", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("adding a value", { test("adding a value", async function (assert) {
template: hbs`{{secret-value-list values=values}}`, await render(hbs`<SecretValueList @values={{this.values}} />`);
async test(assert) { this.set("values", "firstKey|FirstValue\nsecondKey|secondValue");
this.set("values", "firstKey|FirstValue\nsecondKey|secondValue");
await fillIn(".new-value-input.key", "thirdKey"); await fillIn(".new-value-input.key", "thirdKey");
await click(".add-value-btn"); await click(".add-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
2, 2,
"it doesn't add the value to the list if secret is missing" "it doesn't add the value to the list if secret is missing"
); );
await fillIn(".new-value-input.key", ""); await fillIn(".new-value-input.key", "");
await fillIn(".new-value-input.secret", "thirdValue"); await fillIn(".new-value-input.secret", "thirdValue");
await click(".add-value-btn"); await click(".add-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
2, 2,
"it doesn't add the value to the list if key is missing" "it doesn't add the value to the list if key is missing"
); );
await fillIn(".new-value-input.key", "thirdKey"); await fillIn(".new-value-input.key", "thirdKey");
await fillIn(".new-value-input.secret", "thirdValue"); await fillIn(".new-value-input.secret", "thirdValue");
await click(".add-value-btn"); await click(".add-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.deepEqual( assert.deepEqual(
this.values, this.values,
"firstKey|FirstValue\nsecondKey|secondValue\nthirdKey|thirdValue", "firstKey|FirstValue\nsecondKey|secondValue\nthirdKey|thirdValue",
"it adds the value to the list of values" "it adds the value to the list of values"
); );
}, });
});
componentTest("adding an invalid value", { test("adding an invalid value", async function (assert) {
template: hbs`{{secret-value-list values=values}}`, await render(hbs`<SecretValueList @values={{this.values}} />`);
async test(assert) { await fillIn(".new-value-input.key", "someString");
await fillIn(".new-value-input.key", "someString"); await fillIn(".new-value-input.secret", "keyWithAPipe|Hidden");
await fillIn(".new-value-input.secret", "keyWithAPipe|Hidden"); await click(".add-value-btn");
await click(".add-value-btn");
assert.ok( assert.ok(
!exists(".values .value"), !exists(".values .value"),
"it doesn't add the value to the list of values" "it doesn't add the value to the list of values"
); );
assert.deepEqual( assert.deepEqual(
this.values, this.values,
undefined, undefined,
"it doesn't add the value to the list of values" "it doesn't add the value to the list of values"
); );
assert.ok( assert.ok(
queryAll(".validation-error") query(".validation-error").innerText.includes(
.html() I18n.t("admin.site_settings.secret_list.invalid_input")
.indexOf(I18n.t("admin.site_settings.secret_list.invalid_input")) > ),
-1, "it shows validation error"
"it shows validation error" );
); });
},
});
componentTest("changing a value", { test("changing a value", async function (assert) {
template: hbs`{{secret-value-list values=values}}`, await render(hbs`<SecretValueList @values={{this.values}} />`);
async test(assert) { this.set("values", "firstKey|FirstValue\nsecondKey|secondValue");
this.set("values", "firstKey|FirstValue\nsecondKey|secondValue");
await fillIn( await fillIn(
".values .value[data-index='1'] .value-input:first-of-type", ".values .value[data-index='1'] .value-input:first-of-type",
"changedKey" "changedKey"
); );
await blur(".values .value[data-index='1'] .value-input:first-of-type"); await blur(".values .value[data-index='1'] .value-input:first-of-type");
assert.strictEqual( assert.strictEqual(
query(".values .value[data-index='1'] .value-input:first-of-type") query(".values .value[data-index='1'] .value-input:first-of-type").value,
.value, "changedKey"
"changedKey" );
);
await fillIn( await fillIn(
".values .value[data-index='1'] .value-input:last-of-type", ".values .value[data-index='1'] .value-input:last-of-type",
"changedValue" "changedValue"
); );
await blur(".values .value[data-index='1'] .value-input:last-of-type"); await blur(".values .value[data-index='1'] .value-input:last-of-type");
assert.strictEqual( assert.strictEqual(
query(".values .value[data-index='1'] .value-input:last-of-type") query(".values .value[data-index='1'] .value-input:last-of-type").value,
.value, "changedValue"
"changedValue" );
); assert.deepEqual(
assert.deepEqual( this.values,
this.values, "firstKey|FirstValue\nchangedKey|changedValue",
"firstKey|FirstValue\nchangedKey|changedValue", "updates the value list"
"updates the value list" );
); });
},
});
componentTest("removing a value", { test("removing a value", async function (assert) {
template: hbs`{{secret-value-list values=values}}`, await render(hbs`<SecretValueList @values={{this.values}} />`);
async test(assert) { this.set("values", "firstKey|FirstValue\nsecondKey|secondValue");
this.set("values", "firstKey|FirstValue\nsecondKey|secondValue");
await click(".values .value[data-index='0'] .remove-value-btn"); await click(".values .value[data-index='0'] .remove-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
1, 1,
"it removes the value from the list of values" "it removes the value from the list of values"
); );
assert.strictEqual( assert.strictEqual(
this.values, this.values,
"secondKey|secondValue", "secondKey|secondValue",
"it removes the expected value" "it removes the expected value"
); );
}, });
}); });
}
);

View File

@ -1,10 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import selectKit, { import selectKit, {
DEFAULT_CONTENT, DEFAULT_CONTENT,
setDefaultState, setDefaultState,
@ -13,12 +10,11 @@ import { clearCallbacks } from "select-kit/mixins/plugin-api";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
discourseModule("Integration | Component | select-kit:api", function (hooks) { module("Integration | Component | select-kit/api", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.setProperties({ this.setProperties({
// subject: selectKit();
comboBox: selectKit(".combo-box"), comboBox: selectKit(".combo-box"),
singleSelect: selectKit(".single-select:not(.combo-box)"), singleSelect: selectKit(".single-select:not(.combo-box)"),
}); });
@ -28,97 +24,82 @@ discourseModule("Integration | Component | select-kit:api", function (hooks) {
clearCallbacks(); clearCallbacks();
}); });
componentTest("modifySelectKit(identifier).appendContent", { test("modifySelectKit(identifier).appendContent", async function (assert) {
template: hbs` setDefaultState(this, null, { content: DEFAULT_CONTENT });
{{combo-box value=value content=content onChange=onChange}}
{{single-select value=value content=content onChange=onChange}}
`,
beforeEach() { withPluginApi("0.8.43", (api) => {
setDefaultState(this, null, { content: DEFAULT_CONTENT }); api.modifySelectKit("combo-box").appendContent(() => {
return {
withPluginApi("0.8.43", (api) => { id: "alpaca",
api.modifySelectKit("combo-box").appendContent(() => { name: "Alpaca",
return { };
id: "alpaca",
name: "Alpaca",
};
});
api.modifySelectKit("combo-box").appendContent(() => {});
}); });
}, api.modifySelectKit("combo-box").appendContent(() => {});
});
async test(assert) { await render(hbs`
await this.comboBox.expand(); <ComboBox @value={{this.value}} @content={{this.content}} @onChange={{this.onChange}} />
<SingleSelect @value={{this.value}} @content={{this.content}} @onChange={{this.onChange}} />
`);
await this.comboBox.expand();
assert.strictEqual(this.comboBox.rows().length, 4); assert.strictEqual(this.comboBox.rows().length, 4);
const appendedRow = this.comboBox.rowByIndex(3); const appendedRow = this.comboBox.rowByIndex(3);
assert.ok(appendedRow.exists()); assert.ok(appendedRow.exists());
assert.strictEqual(appendedRow.value(), "alpaca"); assert.strictEqual(appendedRow.value(), "alpaca");
await this.comboBox.collapse(); await this.comboBox.collapse();
assert.notOk(this.singleSelect.rowByValue("alpaca").exists()); assert.notOk(this.singleSelect.rowByValue("alpaca").exists());
},
}); });
componentTest("modifySelectKit(identifier).prependContent", { test("modifySelectKit(identifier).prependContent", async function (assert) {
template: hbs` setDefaultState(this, null, { content: DEFAULT_CONTENT });
{{combo-box value=value content=content onChange=onChange}}
{{single-select value=value content=content onChange=onChange}}
`,
beforeEach() { withPluginApi("0.8.43", (api) => {
setDefaultState(this, null, { content: DEFAULT_CONTENT }); api.modifySelectKit("combo-box").prependContent(() => {
return {
withPluginApi("0.8.43", (api) => { id: "alpaca",
api.modifySelectKit("combo-box").prependContent(() => { name: "Alpaca",
return { };
id: "alpaca",
name: "Alpaca",
};
});
api.modifySelectKit("combo-box").prependContent(() => {});
}); });
}, api.modifySelectKit("combo-box").prependContent(() => {});
});
async test(assert) { await render(hbs`
await this.comboBox.expand(); <ComboBox @value={{this.value}} @content={{this.content}} @onChange={{this.onChange}} />
<SingleSelect @value={{this.value}} @content={{this.content}} @onChange={{this.onChange}} />
`);
await this.comboBox.expand();
assert.strictEqual(this.comboBox.rows().length, 4); assert.strictEqual(this.comboBox.rows().length, 4);
const prependedRow = this.comboBox.rowByIndex(0); const prependedRow = this.comboBox.rowByIndex(0);
assert.ok(prependedRow.exists()); assert.ok(prependedRow.exists());
assert.strictEqual(prependedRow.value(), "alpaca"); assert.strictEqual(prependedRow.value(), "alpaca");
await this.comboBox.collapse(); await this.comboBox.collapse();
assert.notOk(this.singleSelect.rowByValue("alpaca").exists()); assert.notOk(this.singleSelect.rowByValue("alpaca").exists());
},
}); });
componentTest("modifySelectKit(identifier).onChange", { test("modifySelectKit(identifier).onChange", async function (assert) {
template: hbs` setDefaultState(this, null, { content: DEFAULT_CONTENT });
withPluginApi("0.8.43", (api) => {
api.modifySelectKit("combo-box").onChange((component, value, item) => {
query("#test").innerText = item.name;
});
});
await render(hbs`
<div id="test"></div> <div id="test"></div>
{{combo-box value=value content=content onChange=onChange}} <ComboBox @value={{this.value}} @content={{this.content}} @onChange={{this.onChange}} />
`, `);
await this.comboBox.expand();
await this.comboBox.selectRowByIndex(0);
beforeEach() { assert.strictEqual(query("#test").innerText, "foo");
setDefaultState(this, null, { content: DEFAULT_CONTENT });
withPluginApi("0.8.43", (api) => {
api.modifySelectKit("combo-box").onChange((component, value, item) => {
queryAll("#test").text(item.name);
});
});
},
async test(assert) {
await this.comboBox.expand();
await this.comboBox.selectRowByIndex(0);
assert.strictEqual(queryAll("#test").text(), "foo");
},
}); });
}); });

View File

@ -1,13 +1,12 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import I18n from "I18n"; import I18n from "I18n";
import createStore from "discourse/tests/helpers/create-store"; import createStore from "discourse/tests/helpers/create-store";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
discourseModule( module(
"Integration | Component | select-kit/category-chooser", "Integration | Component | select-kit/category-chooser",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@ -16,309 +15,265 @@ discourseModule(
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("with value", { test("with value", async function (assert) {
template: hbs` this.set("value", 2);
{{category-chooser
value=value
}}
`,
beforeEach() { await render(hbs`
this.set("value", 2); <CategoryChooser
}, @value={{this.value}}
/>
`);
async test(assert) { assert.strictEqual(this.subject.header().value(), "2");
assert.strictEqual(this.subject.header().value(), "2"); assert.strictEqual(this.subject.header().label(), "feature");
assert.strictEqual(this.subject.header().label(), "feature");
},
}); });
componentTest("with excludeCategoryId", { test("with excludeCategoryId", async function (assert) {
template: hbs` await render(hbs`
{{category-chooser <CategoryChooser
value=value @value={{this.value}}
options=(hash @options={{hash
excludeCategoryId=2 excludeCategoryId=2
) }}
}} />
`, `);
async test(assert) { await this.subject.expand();
await this.subject.expand();
assert.notOk(this.subject.rowByValue(2).exists()); assert.notOk(this.subject.rowByValue(2).exists());
},
}); });
componentTest("with scopedCategoryId", { test("with scopedCategoryId", async function (assert) {
template: hbs` await render(hbs`
{{category-chooser <CategoryChooser
value=value @value={{this.value}}
options=(hash @options={{hash
scopedCategoryId=2 scopedCategoryId=2
) }}
}} />
`, `);
async test(assert) { await this.subject.expand();
await this.subject.expand();
assert.strictEqual(this.subject.rowByIndex(0).title(), "feature"); assert.strictEqual(this.subject.rowByIndex(0).title(), "feature");
assert.strictEqual(this.subject.rowByIndex(0).value(), "2"); assert.strictEqual(this.subject.rowByIndex(0).value(), "2");
assert.strictEqual(this.subject.rowByIndex(1).title(), "spec"); assert.strictEqual(this.subject.rowByIndex(1).title(), "spec");
assert.strictEqual(this.subject.rowByIndex(1).value(), "26"); assert.strictEqual(this.subject.rowByIndex(1).value(), "26");
assert.strictEqual( assert.strictEqual(
this.subject.rows().length, this.subject.rows().length,
2, 2,
"default content is scoped" "default content is scoped"
); );
await this.subject.fillInFilter("bug"); await this.subject.fillInFilter("bug");
assert.strictEqual( assert.strictEqual(
this.subject.rowByIndex(0).name(), this.subject.rowByIndex(0).name(),
"bug", "bug",
"search finds outside of scope" "search finds outside of scope"
); );
},
}); });
componentTest("with prioritizedCategoryId", { test("with prioritizedCategoryId", async function (assert) {
template: hbs` await render(hbs`
{{category-chooser <CategoryChooser
value=value @value={{this.value}}
options=(hash @options={{hash
prioritizedCategoryId=5 prioritizedCategoryId=5
) }}
}} />
`, `);
async test(assert) { await this.subject.expand();
await this.subject.expand();
// The prioritized category // The prioritized category
assert.strictEqual(this.subject.rowByIndex(0).value(), "5"); assert.strictEqual(this.subject.rowByIndex(0).value(), "5");
// The prioritized category's child // The prioritized category's child
assert.strictEqual(this.subject.rowByIndex(1).value(), "22"); assert.strictEqual(this.subject.rowByIndex(1).value(), "22");
// Other categories in the default order // Other categories in the default order
assert.strictEqual(this.subject.rowByIndex(2).value(), "6"); assert.strictEqual(this.subject.rowByIndex(2).value(), "6");
assert.strictEqual(this.subject.rowByIndex(3).value(), "21"); assert.strictEqual(this.subject.rowByIndex(3).value(), "21");
assert.strictEqual(this.subject.rowByIndex(4).value(), "1"); assert.strictEqual(this.subject.rowByIndex(4).value(), "1");
assert.strictEqual( assert.strictEqual(
this.subject.rows().length, this.subject.rows().length,
25, 25,
"all categories are visible" "all categories are visible"
); );
await this.subject.fillInFilter("bug"); await this.subject.fillInFilter("bug");
assert.strictEqual( assert.strictEqual(
this.subject.rowByIndex(0).name(), this.subject.rowByIndex(0).name(),
"bug", "bug",
"search still finds categories" "search still finds categories"
); );
},
}); });
componentTest("with allowUncategorized=null", { test("with allowUncategorized=null", async function (assert) {
template: hbs` this.siteSettings.allow_uncategorized_topics = false;
{{category-chooser
value=value await render(hbs`
options=(hash <CategoryChooser
@value={{this.value}}
@options={{hash
allowUncategorized=null allowUncategorized=null
) }}
}} />
`, `);
beforeEach() { assert.strictEqual(this.subject.header().value(), null);
this.siteSettings.allow_uncategorized_topics = false; assert.strictEqual(this.subject.header().label(), "category…");
},
test(assert) {
assert.strictEqual(this.subject.header().value(), null);
assert.strictEqual(this.subject.header().label(), "category…");
},
}); });
componentTest("with allowUncategorized=null none=true", { test("with allowUncategorized=null none=true", async function (assert) {
template: hbs` this.siteSettings.allow_uncategorized_topics = false;
{{category-chooser
value=value await render(hbs`
options=(hash <CategoryChooser
@value={{this.value}}
@options={{hash
allowUncategorized=null allowUncategorized=null
none=true none=true
) }}
}} />
`, `);
beforeEach() { assert.strictEqual(this.subject.header().value(), null);
this.siteSettings.allow_uncategorized_topics = false; assert.strictEqual(this.subject.header().label(), "(no category)");
},
test(assert) {
assert.strictEqual(this.subject.header().value(), null);
assert.strictEqual(this.subject.header().label(), "(no category)");
},
}); });
componentTest("with disallowed uncategorized, none", { test("with disallowed uncategorized, none", async function (assert) {
template: hbs` I18n.translations[I18n.locale].js.test = { root: "root none label" };
{{category-chooser this.siteSettings.allow_uncategorized_topics = false;
value=value
options=(hash await render(hbs`
<CategoryChooser
@value={{this.value}}
@options={{hash
allowUncategorized=null allowUncategorized=null
none="test.root" none="test.root"
) }}
}} />
`, `);
beforeEach() { assert.strictEqual(this.subject.header().value(), null);
I18n.translations[I18n.locale].js.test = { root: "root none label" }; assert.strictEqual(this.subject.header().label(), "root none label");
this.siteSettings.allow_uncategorized_topics = false;
},
test(assert) {
assert.strictEqual(this.subject.header().value(), null);
assert.strictEqual(this.subject.header().label(), "root none label");
},
}); });
componentTest("with allowed uncategorized", { test("with allowed uncategorized", async function (assert) {
template: hbs` this.siteSettings.allow_uncategorized_topics = true;
{{category-chooser
value=value await render(hbs`
options=(hash <CategoryChooser
@value={{this.value}}
@options={{hash
allowUncategorized=true allowUncategorized=true
) }}
}} />
`, `);
beforeEach() { assert.strictEqual(this.subject.header().value(), null);
this.siteSettings.allow_uncategorized_topics = true; assert.strictEqual(this.subject.header().label(), "uncategorized");
},
test(assert) {
assert.strictEqual(this.subject.header().value(), null);
assert.strictEqual(this.subject.header().label(), "uncategorized");
},
}); });
componentTest("with allowed uncategorized and none=true", { test("with allowed uncategorized and none=true", async function (assert) {
template: hbs` this.siteSettings.allow_uncategorized_topics = true;
{{category-chooser
value=value await render(hbs`
options=(hash <CategoryChooser
@value={{this.value}}
@options={{hash
allowUncategorized=true allowUncategorized=true
none=true none=true
) }}
}} />
`, `);
beforeEach() { assert.strictEqual(this.subject.header().value(), null);
this.siteSettings.allow_uncategorized_topics = true; assert.strictEqual(this.subject.header().label(), "(no category)");
},
test(assert) {
assert.strictEqual(this.subject.header().value(), null);
assert.strictEqual(this.subject.header().label(), "(no category)");
},
}); });
componentTest("with allowed uncategorized and none", { test("with allowed uncategorized and none", async function (assert) {
template: hbs` I18n.translations[I18n.locale].js.test = { root: "root none label" };
{{category-chooser this.siteSettings.allow_uncategorized_topics = true;
value=value
options=(hash await render(hbs`
<CategoryChooser
@value={{this.value}}
@options={{hash
allowUncategorized=true allowUncategorized=true
none="test.root" none="test.root"
) }}
}} />
`, `);
beforeEach() { assert.strictEqual(this.subject.header().value(), null);
I18n.translations[I18n.locale].js.test = { root: "root none label" }; assert.strictEqual(this.subject.header().label(), "root none label");
this.siteSettings.allow_uncategorized_topics = true;
},
test(assert) {
assert.strictEqual(this.subject.header().value(), null);
assert.strictEqual(this.subject.header().label(), "root none label");
},
}); });
componentTest("filter is case insensitive", { test("filter is case insensitive", async function (assert) {
template: hbs` await render(hbs`
{{category-chooser <CategoryChooser
value=value @value={{this.value}}
}} />
`, `);
async test(assert) { await this.subject.expand();
await this.subject.expand(); await this.subject.fillInFilter("bug");
await this.subject.fillInFilter("bug");
assert.strictEqual(this.subject.rows().length, 1); assert.strictEqual(this.subject.rows().length, 1);
assert.strictEqual(this.subject.rowByIndex(0).name(), "bug"); assert.strictEqual(this.subject.rowByIndex(0).name(), "bug");
await this.subject.emptyFilter(); await this.subject.emptyFilter();
await this.subject.fillInFilter("Bug"); await this.subject.fillInFilter("Bug");
assert.strictEqual(this.subject.rows().length, 1); assert.strictEqual(this.subject.rows().length, 1);
assert.strictEqual(this.subject.rowByIndex(0).name(), "bug"); assert.strictEqual(this.subject.rowByIndex(0).name(), "bug");
},
}); });
componentTest("filter works with non english characters", { test("filter works with non english characters", async function (assert) {
template: hbs` const store = createStore();
{{category-chooser store.createRecord("category", {
value=value id: 1,
}} name: "chữ Quốc ngữ",
`, });
beforeEach() { await render(hbs`
const store = createStore(); <CategoryChooser
store.createRecord("category", { @value={{this.value}}
id: 1, />
name: "chữ Quốc ngữ", `);
});
},
async test(assert) { await this.subject.expand();
await this.subject.expand(); await this.subject.fillInFilter("gữ");
await this.subject.fillInFilter("gữ");
assert.strictEqual(this.subject.rows().length, 1); assert.strictEqual(this.subject.rows().length, 1);
assert.strictEqual(this.subject.rowByIndex(0).name(), "chữ Quốc ngữ"); assert.strictEqual(this.subject.rowByIndex(0).name(), "chữ Quốc ngữ");
},
}); });
componentTest("decodes entities in row title", { test("decodes entities in row title", async function (assert) {
template: hbs` const store = createStore();
{{category-chooser store.createRecord("category", {
value=value id: 1,
options=(hash scopedCategoryId=1) name: "cat-with-entities",
}} description_text: "baz &quot;bar ‘foo’",
`, });
beforeEach() { await render(hbs`
const store = createStore(); <CategoryChooser
store.createRecord("category", { @value={{this.value}}
id: 1, @options={{hash scopedCategoryId=1}}
name: "cat-with-entities", />
description_text: "baz &quot;bar ‘foo’", `);
});
},
async test(assert) { await this.subject.expand();
await this.subject.expand();
assert.strictEqual( assert.strictEqual(
this.subject.rowByIndex(0).el().querySelector(".category-desc") this.subject.rowByIndex(0).el().querySelector(".category-desc")
.innerText, .innerText,
'baz "bar ‘foo’' 'baz "bar ‘foo’'
); );
},
}); });
} }
); );

View File

@ -1,11 +1,10 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { import {
ALL_CATEGORIES_ID, ALL_CATEGORIES_ID,
NO_CATEGORIES_ID, NO_CATEGORIES_ID,
} from "select-kit/components/category-drop"; } from "select-kit/components/category-drop";
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import I18n from "I18n"; import I18n from "I18n";
@ -35,428 +34,344 @@ function initCategoriesWithParentCategory(context) {
}); });
} }
discourseModule( module("Integration | Component | select-kit/category-drop", function (hooks) {
"Integration | Component | select-kit/category-drop", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("caretUpIcon", { test("caretUpIcon", async function (assert) {
template: hbs` await render(hbs`
{{category-drop <CategoryDrop
category=value @category={{this.value}}
categories=content @categories={{this.content}}
}} />
`, `);
async test(assert) { const header = this.subject.header().el();
const header = this.subject.header().el();
assert.ok( assert.ok(
header.querySelector(`.d-icon-caret-right`), header.querySelector(`.d-icon-caret-right`),
"it uses the correct default icon" "it uses the correct default icon"
);
},
});
componentTest("none", {
template: hbs`
{{category-drop
category=value
categories=content
}}
`,
async test(assert) {
const text = this.subject.header().label();
assert.strictEqual(
text,
I18n.t("category.all").toLowerCase(),
"it uses the noneLabel"
);
},
});
componentTest("[not staff - TL0] displayCategoryDescription", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
set(this.currentUser, "staff", false);
set(this.currentUser, "trust_level", 0);
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.ok(
row.el().querySelector(".category-desc"),
"it shows category description for newcomers"
);
},
});
componentTest("[not staff - TL1] displayCategoryDescription", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
set(this.currentUser, "moderator", false);
set(this.currentUser, "admin", false);
set(this.currentUser, "trust_level", 1);
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.notOk(
row.el().querySelector(".category-desc"),
"it doesn't shows category description for TL0+"
);
},
});
componentTest("[staff - TL0] displayCategoryDescription", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
set(this.currentUser, "moderator", true);
set(this.currentUser, "trust_level", 0);
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.notOk(
row.el().querySelector(".category-desc"),
"it doesn't show category description for staff"
);
},
});
componentTest("hideParentCategory (default: false)", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.strictEqual(row.value(), this.category.id.toString());
assert.strictEqual(this.category.parent_category_id, undefined);
},
});
componentTest("hideParentCategory (true)", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
options=(hash
hideParentCategory=true
)
}}
`,
beforeEach() {
initCategoriesWithParentCategory(this);
},
async test(assert) {
await this.subject.expand();
const parentRow = this.subject.rowByValue(this.parentCategory.id);
assert.notOk(parentRow.exists(), "the parent row is not showing");
const childCategory = this.categories.firstObject;
const childCategoryId = childCategory.id;
const childRow = this.subject.rowByValue(childCategoryId);
assert.ok(childRow.exists(), "the child row is showing");
const categoryStatus = childRow.el().querySelector(".category-status");
assert.ok(categoryStatus.innerText.trim().match(/^spec/));
},
});
componentTest("allow_uncategorized_topics (true)", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
this.siteSettings.allow_uncategorized_topics = true;
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const uncategorizedCategoryId = this.site.uncategorized_category_id;
const row = this.subject.rowByValue(uncategorizedCategoryId);
assert.ok(row.exists(), "the uncategorized row is showing");
},
});
componentTest("allow_uncategorized_topics (false)", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
this.siteSettings.allow_uncategorized_topics = false;
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const uncategorizedCategoryId = this.site.uncategorized_category_id;
const row = this.subject.rowByValue(uncategorizedCategoryId);
assert.notOk(row.exists(), "the uncategorized row is not showing");
},
});
componentTest("countSubcategories (default: false)", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const category = Category.findById(7);
const row = this.subject.rowByValue(category.id);
const topicCount = row
.el()
.querySelector(".topic-count")
.innerText.trim();
assert.strictEqual(
topicCount,
"× 481",
"it doesn't include the topic count of subcategories"
);
},
});
componentTest("countSubcategories (true)", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
options=(hash
countSubcategories=true
)
}}
`,
beforeEach() {
initCategories(this);
},
async test(assert) {
await this.subject.expand();
const category = Category.findById(7);
const row = this.subject.rowByValue(category.id);
const topicCount = row
.el()
.querySelector(".topic-count")
.innerText.trim();
assert.strictEqual(
topicCount,
"× 584",
"it includes the topic count of subcategories"
);
},
});
componentTest("shortcuts:default", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
initCategories(this);
this.set("category", null);
},
async test(assert) {
await this.subject.expand();
assert.strictEqual(
this.subject.rowByIndex(0).value(),
this.categories.firstObject.id.toString(),
"Shortcuts are not prepended when no category is selected"
);
},
});
componentTest("shortcuts:category is set", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
}}
`,
beforeEach() {
initCategories(this);
},
async test(assert) {
await this.subject.expand();
assert.strictEqual(
this.subject.rowByIndex(0).value(),
ALL_CATEGORIES_ID
);
},
});
componentTest("shortcuts with parentCategory/subCategory=true:default", {
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
options=(hash
subCategory=true
)
}}
`,
beforeEach() {
initCategoriesWithParentCategory(this);
},
async test(assert) {
await this.subject.expand();
assert.strictEqual(
this.subject.rowByIndex(0).value(),
NO_CATEGORIES_ID
);
},
});
componentTest(
"shortcuts with parentCategory/subCategory=true:category is selected",
{
template: hbs`
{{category-drop
category=category
categories=categories
parentCategory=parentCategory
options=(hash
subCategory=true
)
}}
`,
beforeEach() {
initCategoriesWithParentCategory(this);
this.set("category", this.categories.firstObject);
},
async test(assert) {
await this.subject.expand();
assert.strictEqual(
this.subject.rowByIndex(0).value(),
ALL_CATEGORIES_ID
);
assert.strictEqual(
this.subject.rowByIndex(1).value(),
NO_CATEGORIES_ID
);
},
}
); );
});
componentTest("category url", { test("none", async function (assert) {
template: hbs` await render(hbs`
{{category-drop <CategoryDrop
category=category @category={{this.value}}
categories=categories @categories={{this.content}}
parentCategory=parentCategory />
}} `);
`,
beforeEach() { const text = this.subject.header().label();
initCategoriesWithParentCategory(this); assert.strictEqual(
sinon.stub(DiscourseURL, "routeTo"); text,
}, I18n.t("category.all").toLowerCase(),
"it uses the noneLabel"
);
});
async test(assert) { test("[not staff - TL0] displayCategoryDescription", async function (assert) {
await this.subject.expand(); set(this.currentUser, "staff", false);
await this.subject.selectRowByValue(26); set(this.currentUser, "trust_level", 0);
assert.ok( initCategories(this);
DiscourseURL.routeTo.calledWith("/c/feature/spec/26"),
"it builds a correct URL" await render(hbs`
); <CategoryDrop
}, @category={{this.category}}
}); @categories={{this.categories}}
} @parentCategory={{this.parentCategory}}
); />
`);
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.ok(
row.el().querySelector(".category-desc"),
"it shows category description for newcomers"
);
});
test("[not staff - TL1] displayCategoryDescription", async function (assert) {
set(this.currentUser, "moderator", false);
set(this.currentUser, "admin", false);
set(this.currentUser, "trust_level", 1);
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.notOk(
row.el().querySelector(".category-desc"),
"it doesn't shows category description for TL0+"
);
});
test("[staff - TL0] displayCategoryDescription", async function (assert) {
set(this.currentUser, "moderator", true);
set(this.currentUser, "trust_level", 0);
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.notOk(
row.el().querySelector(".category-desc"),
"it doesn't show category description for staff"
);
});
test("hideParentCategory (default: false)", async function (assert) {
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
const row = this.subject.rowByValue(this.category.id);
assert.strictEqual(row.value(), this.category.id.toString());
assert.strictEqual(this.category.parent_category_id, undefined);
});
test("hideParentCategory (true)", async function (assert) {
initCategoriesWithParentCategory(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
@options={{hash
hideParentCategory=true
}}
/>
`);
await this.subject.expand();
const parentRow = this.subject.rowByValue(this.parentCategory.id);
assert.notOk(parentRow.exists(), "the parent row is not showing");
const childCategory = this.categories.firstObject;
const childCategoryId = childCategory.id;
const childRow = this.subject.rowByValue(childCategoryId);
assert.ok(childRow.exists(), "the child row is showing");
const categoryStatus = childRow.el().querySelector(".category-status");
assert.ok(categoryStatus.innerText.trim().match(/^spec/));
});
test("allow_uncategorized_topics (true)", async function (assert) {
this.siteSettings.allow_uncategorized_topics = true;
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
const uncategorizedCategoryId = this.site.uncategorized_category_id;
const row = this.subject.rowByValue(uncategorizedCategoryId);
assert.ok(row.exists(), "the uncategorized row is showing");
});
test("allow_uncategorized_topics (false)", async function (assert) {
this.siteSettings.allow_uncategorized_topics = false;
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
const uncategorizedCategoryId = this.site.uncategorized_category_id;
const row = this.subject.rowByValue(uncategorizedCategoryId);
assert.notOk(row.exists(), "the uncategorized row is not showing");
});
test("countSubcategories (default: false)", async function (assert) {
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
const category = Category.findById(7);
const row = this.subject.rowByValue(category.id);
const topicCount = row.el().querySelector(".topic-count").innerText.trim();
assert.strictEqual(
topicCount,
"× 481",
"it doesn't include the topic count of subcategories"
);
});
test("countSubcategories (true)", async function (assert) {
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
@options={{hash
countSubcategories=true
}}
/>
`);
await this.subject.expand();
const category = Category.findById(7);
const row = this.subject.rowByValue(category.id);
const topicCount = row.el().querySelector(".topic-count").innerText.trim();
assert.strictEqual(
topicCount,
"× 584",
"it includes the topic count of subcategories"
);
});
test("shortcuts:default", async function (assert) {
initCategories(this);
this.set("category", null);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
assert.strictEqual(
this.subject.rowByIndex(0).value(),
this.categories.firstObject.id.toString(),
"Shortcuts are not prepended when no category is selected"
);
});
test("shortcuts:category is set", async function (assert) {
initCategories(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
assert.strictEqual(this.subject.rowByIndex(0).value(), ALL_CATEGORIES_ID);
});
test("shortcuts with parentCategory/subCategory=true:default", async function (assert) {
initCategoriesWithParentCategory(this);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
@options={{hash
subCategory=true
}}
/>
`);
await this.subject.expand();
assert.strictEqual(this.subject.rowByIndex(0).value(), NO_CATEGORIES_ID);
});
test("shortcuts with parentCategory/subCategory=true:category is selected", async function (assert) {
initCategoriesWithParentCategory(this);
this.set("category", this.categories.firstObject);
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
@options={{hash
subCategory=true
}}
/>
`);
await this.subject.expand();
assert.strictEqual(this.subject.rowByIndex(0).value(), ALL_CATEGORIES_ID);
assert.strictEqual(this.subject.rowByIndex(1).value(), NO_CATEGORIES_ID);
});
test("category url", async function (assert) {
initCategoriesWithParentCategory(this);
sinon.stub(DiscourseURL, "routeTo");
await render(hbs`
<CategoryDrop
@category={{this.category}}
@categories={{this.categories}}
@parentCategory={{this.parentCategory}}
/>
`);
await this.subject.expand();
await this.subject.selectRowByValue(26);
assert.ok(
DiscourseURL.routeTo.calledWith("/c/feature/spec/26"),
"it builds a correct URL"
);
});
});

View File

@ -1,8 +1,6 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import { click } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -14,98 +12,87 @@ const DEFAULT_CONTENT = [
const DEFAULT_VALUE = 1; const DEFAULT_VALUE = 1;
const setDefaultState = (ctx, options) => { const setDefaultState = (ctx, options = {}) => {
const properties = Object.assign( const properties = Object.assign(
{ {
content: DEFAULT_CONTENT, content: DEFAULT_CONTENT,
value: DEFAULT_VALUE, value: DEFAULT_VALUE,
}, },
options || {} options
); );
ctx.setProperties(properties); ctx.setProperties(properties);
}; };
discourseModule( module("Integration | Component | select-kit/combo-box", function (hooks) {
"Integration | Component | select-kit/combo-box", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("options.clearable", { test("options.clearable", async function (assert) {
template: hbs` setDefaultState(this, {
{{combo-box clearable: true,
value=value onChange: (value) => {
content=content this.set("value", value);
onChange=onChange
options=(hash clearable=clearable)
}}
`,
beforeEach() {
setDefaultState(this, {
clearable: true,
onChange: (value) => {
this.set("value", value);
},
});
},
async test(assert) {
const header = this.subject.header();
assert.ok(
header.el().querySelector(".btn-clear"),
"it shows the clear button"
);
assert.strictEqual(header.value(), DEFAULT_VALUE.toString());
await click(header.el().querySelector(".btn-clear"));
assert.notOk(
header.el().querySelector(".btn-clear"),
"it hides the clear button"
);
assert.strictEqual(header.value(), null);
}, },
}); });
componentTest("options.{caretUpIcon,caretDownIcon}", { await render(hbs`
template: hbs` <ComboBox
{{combo-box @value={{this.value}}
value=value @content={{this.content}}
content=content @onChange={{this.onChange}}
options=(hash @options={{hash clearable=this.clearable}}
/>
`);
const header = this.subject.header();
assert.ok(
header.el().querySelector(".btn-clear"),
"it shows the clear button"
);
assert.strictEqual(header.value(), DEFAULT_VALUE.toString());
await click(header.el().querySelector(".btn-clear"));
assert.notOk(
header.el().querySelector(".btn-clear"),
"it hides the clear button"
);
assert.strictEqual(header.value(), null);
});
test("options.{caretUpIcon,caretDownIcon}", async function (assert) {
setDefaultState(this, {
caretUpIcon: "pencil-alt",
caretDownIcon: "trash-alt",
});
await render(hbs`
<ComboBox
@value={{this.value}}
@content={{this.content}}
@options={{hash
caretUpIcon=caretUpIcon caretUpIcon=caretUpIcon
caretDownIcon=caretDownIcon caretDownIcon=caretDownIcon
) }}
}} />
`, `);
beforeEach() { const header = this.subject.header().el();
setDefaultState(this, {
caretUpIcon: "pencil-alt",
caretDownIcon: "trash-alt",
});
},
async test(assert) { assert.ok(
const header = this.subject.header().el(); header.querySelector(`.d-icon-${this.caretDownIcon}`),
"it uses the icon provided"
);
assert.ok( await this.subject.expand();
header.querySelector(`.d-icon-${this.caretDownIcon}`),
"it uses the icon provided"
);
await this.subject.expand(); assert.ok(
header.querySelector(`.d-icon-${this.caretUpIcon}`),
assert.ok( "it uses the icon provided"
header.querySelector(`.d-icon-${this.caretUpIcon}`), );
"it uses the icon provided" });
); });
},
});
}
);

View File

@ -1,7 +1,6 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -27,7 +26,7 @@ const setDefaultState = (ctx, options) => {
ctx.setProperties(properties); ctx.setProperties(properties);
}; };
discourseModule( module(
"Integration | Component | select-kit/dropdown-select-box", "Integration | Component | select-kit/dropdown-select-box",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@ -36,86 +35,74 @@ discourseModule(
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("selection behavior", { test("selection behavior", async function (assert) {
template: hbs` setDefaultState(this);
{{dropdown-select-box
value=value
content=content
}}
`,
beforeEach() { await render(hbs`
setDefaultState(this); <DropdownSelectBox
}, @value={{this.value}}
@content={{this.content}}
/>
`);
async test(assert) { await this.subject.expand();
await this.subject.expand(); assert.ok(this.subject.isExpanded());
assert.ok(this.subject.isExpanded());
await this.subject.selectRowByValue(DEFAULT_VALUE); await this.subject.selectRowByValue(DEFAULT_VALUE);
assert.notOk( assert.notOk(
this.subject.isExpanded(), this.subject.isExpanded(),
"it collapses the dropdown on select" "it collapses the dropdown on select"
); );
},
}); });
componentTest("options.showFullTitle=false", { test("options.showFullTitle=false", async function (assert) {
template: hbs` setDefaultState(this, {
{{dropdown-select-box value: null,
value=value showFullTitle: false,
content=content none: "test_none",
options=(hash });
icon="times"
showFullTitle=showFullTitle
none=none
)
}}
`,
beforeEach() { await render(hbs`
setDefaultState(this, { <DropdownSelectBox
value: null, @value={{this.value}}
showFullTitle: false, @content={{this.content}}
none: "test_none", @options={{hash
}); icon="times"
}, showFullTitle=this.showFullTitle
none=this.none
}}
/>
`);
async test(assert) { assert.notOk(
assert.notOk( this.subject.header().el().querySelector(".selected-name"),
this.subject.header().el().querySelector(".selected-name"), "it hides the text of the selected item"
"it hides the text of the selected item" );
);
assert.strictEqual( assert.strictEqual(
this.subject.header().el().getAttribute("title"), this.subject.header().el().getAttribute("title"),
"[en.test_none]", "[en.test_none]",
"it adds a title attribute to the button" "it adds a title attribute to the button"
); );
},
}); });
componentTest("options.showFullTitle=true", { test("options.showFullTitle=true", async function (assert) {
template: hbs` setDefaultState(this, { showFullTitle: true });
{{dropdown-select-box
value=value
content=content
options=(hash
showFullTitle=showFullTitle
)
}}
`,
beforeEach() { await render(hbs`
setDefaultState(this, { showFullTitle: true }); <DropdownSelectBox
}, @value={{this.value}}
@content={{this.content}}
@options={{hash
showFullTitle=this.showFullTitle
}}
/>
`);
async test(assert) { assert.ok(
assert.ok( this.subject.header().el().querySelector(".selected-name"),
this.subject.header().el().querySelector(".selected-name"), "it shows the text of the selected item"
"it shows the text of the selected item" );
);
},
}); });
} }
); );

View File

@ -1,45 +1,50 @@
import selectKit from "discourse/tests/helpers/select-kit-helper"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { fillIn, render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test";
import { import {
discourseModule,
exists, exists,
fakeTime, fakeTime,
queryAll, queryAll,
} from "discourse/tests/helpers/qunit-helpers"; } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import I18n from "I18n"; import I18n from "I18n";
import { fillIn } from "@ember/test-helpers";
discourseModule("Unit | Lib | select-kit/future-date-input", function (hooks) { function getOptions() {
setupRenderingTest(hooks); return Array.from(
queryAll(`.select-kit-collection .select-kit-row`).map(
(_, span) => span.dataset.name
)
);
}
hooks.beforeEach(function () { module(
this.set("subject", selectKit()); "Integration | Component | select-kit/future-date-input",
}); function (hooks) {
setupRenderingTest(hooks);
hooks.afterEach(function () { hooks.beforeEach(function () {
if (this.clock) { this.set("subject", selectKit());
this.clock.restore(); });
}
});
componentTest("rendering and expanding", { hooks.afterEach(function () {
template: hbs` this.clock?.restore();
{{future-date-input });
options=(hash
test("rendering and expanding", async function (assert) {
await render(hbs`
<FutureDateInput
@options={{hash
none="time_shortcut.select_timeframe" none="time_shortcut.select_timeframe"
) }}
}} />
`, `);
async test(assert) {
assert.ok(exists(".future-date-input-selector"), "Selector is rendered"); assert.ok(exists(".future-date-input-selector"), "Selector is rendered");
assert.ok( assert.strictEqual(
this.subject.header().label() === this.subject.header().label(),
I18n.t("time_shortcut.select_timeframe"), I18n.t("time_shortcut.select_timeframe"),
"Default text is rendered" "Default text is rendered"
); );
@ -49,18 +54,14 @@ discourseModule("Unit | Lib | select-kit/future-date-input", function (hooks) {
exists(".select-kit-collection"), exists(".select-kit-collection"),
"List of options is rendered" "List of options is rendered"
); );
}, });
});
componentTest("renders default options", { test("renders default options", async function (assert) {
template: hbs`{{future-date-input}}`,
beforeEach() {
const monday = "2100-12-13T08:00:00"; const monday = "2100-12-13T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true); this.clock = fakeTime(monday, this.currentUser.timezone, true);
},
async test(assert) { await render(hbs`<FutureDateInput />`);
await this.subject.expand(); await this.subject.expand();
const options = getOptions(); const options = getOptions();
const expected = [ const expected = [
@ -80,61 +81,53 @@ discourseModule("Unit | Lib | select-kit/future-date-input", function (hooks) {
]; ];
assert.deepEqual(options, expected); assert.deepEqual(options, expected);
}, });
});
componentTest("shows 'Custom date and time' by default", { test("shows 'Custom date and time' by default", async function (assert) {
template: hbs`{{future-date-input}}`, await render(hbs`<FutureDateInput />`);
async test(assert) {
await this.subject.expand(); await this.subject.expand();
const options = getOptions(); const options = getOptions();
const customDateAndTime = I18n.t("time_shortcut.custom"); const customDateAndTime = I18n.t("time_shortcut.custom");
assert.ok(options.includes(customDateAndTime)); assert.ok(options.includes(customDateAndTime));
}, });
});
componentTest("doesn't show 'Custom date and time' if disabled", { test("doesn't show 'Custom date and time' if disabled", async function (assert) {
template: hbs` await render(hbs`
{{future-date-input <FutureDateInput
includeDateTime=false @includeDateTime={{false}}
}} />
`, `);
async test(assert) {
await this.subject.expand(); await this.subject.expand();
const options = getOptions(); const options = getOptions();
const customDateAndTime = I18n.t("time_shortcut.custom"); const customDateAndTime = I18n.t("time_shortcut.custom");
assert.notOk(options.includes(customDateAndTime)); assert.notOk(options.includes(customDateAndTime));
}, });
});
componentTest("shows the now option if enabled", { test("shows the now option if enabled", async function (assert) {
template: hbs` await render(hbs`
{{future-date-input <FutureDateInput
includeNow=true @includeNow={{true}}
}} />
`, `);
async test(assert) {
await this.subject.expand(); await this.subject.expand();
const options = getOptions(); const options = getOptions();
const now = I18n.t("time_shortcut.now"); const now = I18n.t("time_shortcut.now");
assert.ok(options.includes(now)); assert.ok(options.includes(now));
}, });
});
componentTest("changing date/time updates the input correctly", { test("changing date/time updates the input correctly", async function (assert) {
template: hbs`{{future-date-input input=input onChangeInput=(action (mut input))}}`,
beforeEach() {
this.set("input", moment("2032-01-01 11:10")); this.set("input", moment("2032-01-01 11:10"));
},
async test(assert) { await render(
hbs`<FutureDateInput @input={{this.input}} @onChangeInput={{action (mut input)}} />`
);
await fillIn(".time-input", "11:15"); await fillIn(".time-input", "11:15");
assert.ok(this.input.includes("2032-01-01")); assert.ok(this.input.includes("2032-01-01"));
@ -144,14 +137,6 @@ discourseModule("Unit | Lib | select-kit/future-date-input", function (hooks) {
assert.ok(this.input.includes("2033-01-01")); assert.ok(this.input.includes("2033-01-01"));
assert.ok(this.input.includes("11:15")); assert.ok(this.input.includes("11:15"));
}, });
});
function getOptions() {
return Array.from(
queryAll(`.select-kit-collection .select-kit-row`).map(
(_, span) => span.dataset.name
)
);
} }
}); );

View File

@ -1,31 +0,0 @@
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
discourseModule(
"Integration | Component | site-setting | host-list",
function (hooks) {
setupRenderingTest(hooks);
componentTest("displays setting value", {
template: hbs`{{site-setting setting=setting}}`,
beforeEach() {
this.set("setting", {
setting: "blocked_onebox_domains",
value: "a.com|b.com",
type: "host_list",
});
},
async test(assert) {
assert.strictEqual(
query(".formatted-selection").innerText,
"a.com, b.com"
);
},
});
}
);

View File

@ -1,41 +1,33 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
discourseModule( module("Integration | Component | select-kit/list-setting", function (hooks) {
"Integration | Component | select-kit/list-setting", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("default", { test("default", async function (assert) {
template: hbs` this.set("value", ["bold", "italic"]);
{{list-setting this.set("choices", ["bold", "italic", "underline"]);
value=value
choices=choices
}}
`,
beforeEach() { await render(hbs`
this.set("value", ["bold", "italic"]); <ListSetting
this.set("choices", ["bold", "italic", "underline"]); @value={{this.value}}
}, @choices={{this.choices}}
/>
`);
async test(assert) { assert.strictEqual(this.subject.header().name(), "bold,italic");
assert.strictEqual(this.subject.header().name(), "bold,italic"); assert.strictEqual(this.subject.header().value(), "bold,italic");
assert.strictEqual(this.subject.header().value(), "bold,italic");
await this.subject.expand(); await this.subject.expand();
assert.strictEqual(this.subject.rows().length, 1); assert.strictEqual(this.subject.rows().length, 1);
assert.strictEqual(this.subject.rowByIndex(0).value(), "underline"); assert.strictEqual(this.subject.rowByIndex(0).value(), "underline");
}, });
}); });
}
);

View File

@ -1,16 +1,12 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { query, queryAll } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n"; import I18n from "I18n";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
discourseModule( module(
"Integration | Component | select-kit/mini-tag-chooser", "Integration | Component | select-kit/mini-tag-chooser",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@ -19,97 +15,83 @@ discourseModule(
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("displays tags", { test("displays tags", async function (assert) {
template: hbs`{{mini-tag-chooser value=value}}`, this.set("value", ["foo", "bar"]);
beforeEach() { await render(hbs`<MiniTagChooser @value={{this.value}} />`);
this.set("value", ["foo", "bar"]);
},
async test(assert) { assert.strictEqual(this.subject.header().value(), "foo,bar");
assert.strictEqual(this.subject.header().value(), "foo,bar");
},
}); });
componentTest("create a tag", { test("create a tag", async function (assert) {
template: hbs`{{mini-tag-chooser value=value}}`, this.set("value", ["foo", "bar"]);
beforeEach() { await render(hbs`<MiniTagChooser @value={{this.value}} />`);
this.set("value", ["foo", "bar"]);
},
async test(assert) { assert.strictEqual(this.subject.header().value(), "foo,bar");
assert.strictEqual(this.subject.header().value(), "foo,bar");
await this.subject.expand(); await this.subject.expand();
await this.subject.fillInFilter("mon"); await this.subject.fillInFilter("mon");
assert.strictEqual( assert.deepEqual(
queryAll(".select-kit-row").text().trim(), [...queryAll(".select-kit-row")].map((el) => el.textContent.trim()),
"monkey x1\ngazelle x2" ["monkey x1", "gazelle x2"]
); );
await this.subject.fillInFilter("key"); await this.subject.fillInFilter("key");
assert.strictEqual( assert.deepEqual(
queryAll(".select-kit-row").text().trim(), [...queryAll(".select-kit-row")].map((el) => el.textContent.trim()),
"monkey x1\ngazelle x2" ["monkey x1", "gazelle x2"]
); );
await this.subject.selectRowByValue("monkey"); await this.subject.selectRowByValue("monkey");
assert.strictEqual(this.subject.header().value(), "foo,bar,monkey"); assert.strictEqual(this.subject.header().value(), "foo,bar,monkey");
},
}); });
componentTest("max_tags_per_topic", { test("max_tags_per_topic", async function (assert) {
template: hbs`{{mini-tag-chooser value=value}}`, this.set("value", ["foo", "bar"]);
this.siteSettings.max_tags_per_topic = 2;
beforeEach() { await render(hbs`<MiniTagChooser @value={{this.value}} />`);
this.set("value", ["foo", "bar"]);
this.siteSettings.max_tags_per_topic = 2;
},
async test(assert) { assert.strictEqual(this.subject.header().value(), "foo,bar");
assert.strictEqual(this.subject.header().value(), "foo,bar");
await this.subject.expand(); await this.subject.expand();
await this.subject.fillInFilter("baz"); await this.subject.fillInFilter("baz");
await this.subject.selectRowByValue("monkey"); await this.subject.selectRowByValue("monkey");
const error = queryAll(".select-kit-error").text(); const error = query(".select-kit-error").innerText;
assert.strictEqual( assert.strictEqual(
error, error,
I18n.t("select_kit.max_content_reached", { I18n.t("select_kit.max_content_reached", {
count: this.siteSettings.max_tags_per_topic, count: this.siteSettings.max_tags_per_topic,
}) })
); );
},
}); });
componentTest("required_tag_group", { test("required_tag_group", async function (assert) {
template: hbs`{{mini-tag-chooser value=value options=(hash categoryId=1)}}`, this.set("value", ["foo", "bar"]);
beforeEach() { await render(
this.set("value", ["foo", "bar"]); hbs`<MiniTagChooser @value={{this.value}} @options={{hash categoryId=1}} />`
}, );
async test(assert) { assert.strictEqual(this.subject.header().value(), "foo,bar");
assert.strictEqual(this.subject.header().value(), "foo,bar");
await this.subject.expand(); await this.subject.expand();
assert.strictEqual( assert.strictEqual(
query("input[name=filter-input-search]").placeholder, query("input[name=filter-input-search]").placeholder,
I18n.t("tagging.choose_for_topic_required_group", { I18n.t("tagging.choose_for_topic_required_group", {
count: 1, count: 1,
name: "monkey group", name: "monkey group",
}) })
); );
await this.subject.selectRowByValue("monkey"); await this.subject.selectRowByValue("monkey");
assert.strictEqual( assert.strictEqual(
query("input[name=filter-input-search]").placeholder, query("input[name=filter-input-search]").placeholder,
I18n.t("select_kit.filter_placeholder") I18n.t("select_kit.filter_placeholder")
); );
},
}); });
} }
); );

View File

@ -1,7 +1,6 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -22,120 +21,83 @@ const setDefaultState = (ctx, options) => {
ctx.setProperties(properties); ctx.setProperties(properties);
}; };
discourseModule( module("Integration | Component | select-kit/multi-select", function (hooks) {
"Integration | Component | select-kit/multi-select", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("content", { test("content", async function (assert) {
template: hbs` setDefaultState(this);
{{multi-select
value=value
content=content
}}
`,
beforeEach() { await render(hbs`
setDefaultState(this); <MultiSelect
}, @value={{this.value}}
@content={{this.content}}
/>
`);
async test(assert) { await this.subject.expand();
await this.subject.expand();
const content = this.subject.displayedContent(); const content = this.subject.displayedContent();
assert.strictEqual(content.length, 3, "it shows rows"); assert.strictEqual(content.length, 3, "it shows rows");
assert.strictEqual( assert.strictEqual(
content[0].name, content[0].name,
this.content.firstObject.name, this.content.firstObject.name,
"it has the correct name" "it has the correct name"
); );
assert.strictEqual( assert.strictEqual(
content[0].id, content[0].id,
this.content.firstObject.id.toString(), this.content.firstObject.id.toString(),
"it has the correct value" "it has the correct value"
); );
assert.strictEqual( assert.strictEqual(
this.subject.header().value(), this.subject.header().value(),
null, null,
"it doesn't set a value from the content" "it doesn't set a value from the content"
); );
}, });
});
}
);
discourseModule( test("maximum=1", async function (assert) {
"Integration | Component | select-kit/multi-select | maximum=1", setDefaultState(this);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { await render(hbs`
this.set("subject", selectKit()); <MultiSelect
}); @value={{this.value}}
@content={{this.content}}
@options={{hash maximum=1}}
/>
`);
componentTest("content", { await this.subject.expand();
template: hbs` await this.subject.selectRowByValue(1);
{{multi-select
value=value
content=content
options=(hash maximum=1)
}}
`,
beforeEach() { assert.notOk(this.subject.isExpanded(), "it closes the dropdown");
setDefaultState(this);
},
async test(assert) { await this.subject.expand();
await this.subject.expand(); await this.subject.deselectItemByValue(1);
await this.subject.selectRowByValue(1);
assert.notOk(this.subject.isExpanded(), "it closes the dropdown"); assert.ok(
this.subject.isExpanded(),
"it doesn’t close the dropdown when no selection has been made"
);
});
await this.subject.expand(); test("maximum=2", async function (assert) {
await this.subject.deselectItemByValue(1); setDefaultState(this);
assert.ok( await render(hbs`
this.subject.isExpanded(), <MultiSelect
"it doesn’t close the dropdown when no selection has been made" @value={{this.value}}
); @content={{this.content}}
}, @options={{hash maximum=2}}
}); />
} `);
);
discourseModule( await this.subject.expand();
"Integration | Component | select-kit/multi-select | maximum=2", await this.subject.selectRowByValue(1);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { assert.ok(this.subject.isExpanded(), "it doesn’t close the dropdown");
this.set("subject", selectKit()); });
}); });
componentTest("content", {
template: hbs`
{{multi-select
value=value
content=content
options=(hash maximum=2)
}}
`,
beforeEach() {
setDefaultState(this);
},
async test(assert) {
await this.subject.expand();
await this.subject.selectRowByValue(1);
assert.ok(this.subject.isExpanded(), "it doesn’t close the dropdown");
},
});
}
);

View File

@ -1,13 +1,12 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import selectKit, { import selectKit, {
setDefaultState, setDefaultState,
} from "discourse/tests/helpers/select-kit-helper"; } from "discourse/tests/helpers/select-kit-helper";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module(
"Integration | Component | select-kit/notifications-button", "Integration | Component | select-kit/notifications-button",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@ -16,40 +15,35 @@ discourseModule(
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("default", { test("default", async function (assert) {
template: hbs` this.set("value", 1);
{{notifications-button setDefaultState(this, 1, { i18nPrefix: "pre", i18nPostfix: "post" });
value=value
options=(hash
i18nPrefix=i18nPrefix
i18nPostfix=i18nPostfix
)
}}
`,
beforeEach() { await render(hbs`
this.set("value", 1); <NotificationsButton
@value={{this.value}}
@options={{hash
i18nPrefix=this.i18nPrefix
i18nPostfix=this.i18nPostfix
}}
/>
`);
setDefaultState(this, 1, { i18nPrefix: "pre", i18nPostfix: "post" }); assert.ok(this.subject.header().value());
},
async test(assert) { assert.ok(
assert.ok(this.subject.header().value()); this.subject
.header()
.label()
.includes(`${this.i18nPrefix}.regular${this.i18nPostfix}`),
"it shows the regular choice when value is not set"
);
assert.ok( const icon = this.subject.header().icon();
this.subject assert.ok(
.header() icon.classList.contains("d-icon-d-regular"),
.label() "it shows the correct icon"
.includes(`${this.i18nPrefix}.regular${this.i18nPostfix}`), );
"it shows the regular choice when value is not set"
);
const icon = this.subject.header().icon();
assert.ok(
icon.classList.contains("d-icon-d-regular"),
"it shows the correct icon"
);
},
}); });
} }
); );

View File

@ -1,8 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -15,49 +14,42 @@ const buildTopic = function (pinned = true) {
}); });
}; };
discourseModule( module("Integration | Component | select-kit/pinned-options", function (hooks) {
"Integration | Component | select-kit/pinned-options", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("unpinning", { test("unpinning", async function (assert) {
template: hbs`{{pinned-options value=topic.pinned topic=topic}}`, this.siteSettings.automatically_unpin_topics = false;
this.set("topic", buildTopic());
beforeEach() { await render(
this.siteSettings.automatically_unpin_topics = false; hbs`<PinnedOptions @value={{this.topic.pinned}} @topic={{this.topic}} />`
this.set("topic", buildTopic()); );
},
async test(assert) { assert.strictEqual(this.subject.header().name(), "pinned");
assert.strictEqual(this.subject.header().name(), "pinned");
await this.subject.expand(); await this.subject.expand();
await this.subject.selectRowByValue("unpinned"); await this.subject.selectRowByValue("unpinned");
assert.strictEqual(this.subject.header().name(), "unpinned"); assert.strictEqual(this.subject.header().name(), "unpinned");
}, });
});
componentTest("pinning", { test("pinning", async function (assert) {
template: hbs`{{pinned-options value=topic.pinned topic=topic}}`, this.siteSettings.automatically_unpin_topics = false;
this.set("topic", buildTopic(false));
beforeEach() { await render(
this.siteSettings.automatically_unpin_topics = false; hbs`<PinnedOptions @value={{this.topic.pinned}} @topic={{this.topic}} />`
this.set("topic", buildTopic(false)); );
},
async test(assert) { assert.strictEqual(this.subject.header().name(), "unpinned");
assert.strictEqual(this.subject.header().name(), "unpinned");
await this.subject.expand(); await this.subject.expand();
await this.subject.selectRowByValue("pinned"); await this.subject.selectRowByValue("pinned");
assert.strictEqual(this.subject.header().name(), "pinned"); assert.strictEqual(this.subject.header().name(), "pinned");
}, });
}); });
}
);

View File

@ -1,8 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import I18n from "I18n"; import I18n from "I18n";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -30,421 +29,366 @@ const setDefaultState = (ctx, options) => {
ctx.setProperties(properties); ctx.setProperties(properties);
}; };
discourseModule( module("Integration | Component | select-kit/single-select", function (hooks) {
"Integration | Component | select-kit/single-select", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("content", { test("content", async function (assert) {
template: hbs`{{single-select content=content}}`, setDefaultState(this);
beforeEach() { await render(hbs`<SingleSelect @content={{this.content}} />`);
setDefaultState(this);
},
async test(assert) { await this.subject.expand();
await this.subject.expand();
const content = this.subject.displayedContent(); const content = this.subject.displayedContent();
assert.strictEqual(content.length, 3, "it shows rows"); assert.strictEqual(content.length, 3, "it shows rows");
assert.strictEqual( assert.strictEqual(
content[0].name, content[0].name,
this.content.firstObject.name, this.content.firstObject.name,
"it has the correct name" "it has the correct name"
); );
assert.strictEqual( assert.strictEqual(
content[0].id, content[0].id,
this.content.firstObject.id.toString(), this.content.firstObject.id.toString(),
"it has the correct value" "it has the correct value"
); );
assert.strictEqual( assert.strictEqual(
this.subject.header().value(), this.subject.header().value(),
null, null,
"it doesn't set a value from the content" "it doesn't set a value from the content"
); );
}, });
});
componentTest("value", { test("value", async function (assert) {
template: hbs` setDefaultState(this);
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
}}
`,
beforeEach() { await render(hbs`
setDefaultState(this); <SingleSelect
}, @value={{this.value}}
@content={{this.content}}
@nameProperty={{this.nameProperty}}
@valueProperty={{this.valueProperty}}
@onChange={{this.onChange}}
/>
`);
test(assert) { assert.strictEqual(
assert.strictEqual( this.subject.header().value(this.content),
this.subject.header().value(this.content), "1",
"1", "it selects the correct content to display"
"it selects the correct content to display" );
); });
},
});
componentTest("options.filterable", { test("options.filterable", async function (assert) {
template: hbs` setDefaultState(this, { filterable: true });
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
options=(hash
filterable=filterable
)
}}
`,
beforeEach() { await render(hbs`
setDefaultState(this, { filterable: true }); <SingleSelect
}, @value={{this.value}}
@content={{this.content}}
async test(assert) { @nameProperty={{this.nameProperty}}
await this.subject.expand(); @valueProperty={{this.valueProperty}}
assert.ok(this.subject.filter().exists(), "it shows the filter"); @onChange={{this.onChange}}
@options={{hash
const filter = this.subject.displayedContent()[1].name; filterable=this.filterable
await this.subject.fillInFilter(filter);
assert.strictEqual(
this.subject.displayedContent()[0].name,
filter,
"it filters the list"
);
},
});
componentTest("options.limitMatches", {
template: hbs`
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
options=(hash
limitMatches=limitMatches
filterable=filterable
)
}}
`,
beforeEach() {
setDefaultState(this, { limitMatches: 1, filterable: true });
},
async test(assert) {
await this.subject.expand();
await this.subject.fillInFilter("ba");
assert.strictEqual(
this.subject.displayedContent().length,
1,
"it returns only 1 result"
);
},
});
componentTest("valueAttribute (deprecated)", {
template: hbs`
{{single-select
value=value
content=content
valueAttribute="value"
}}
`,
beforeEach() {
this.set("value", "normal");
const content = [
{ name: "Smallest", value: "smallest" },
{ name: "Smaller", value: "smaller" },
{ name: "Normal", value: "normal" },
{ name: "Larger", value: "larger" },
{ name: "Largest", value: "largest" },
];
this.set("content", content);
},
async test(assert) {
await this.subject.expand();
assert.strictEqual(this.subject.selectedRow().value(), this.value);
},
});
componentTest("none:string", {
template: hbs`
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
options=(hash
none="test.none"
)
}}
`,
beforeEach() {
I18n.translations[I18n.locale].js.test = { none: "(default)" };
setDefaultState(this, { value: 1 });
},
async test(assert) {
await this.subject.expand();
const noneRow = this.subject.rowByIndex(0);
assert.strictEqual(noneRow.value(), null);
assert.strictEqual(noneRow.name(), I18n.t("test.none"));
},
});
componentTest("none:object", {
template: hbs`
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
options=(hash
none=none
)
}}
`,
beforeEach() {
setDefaultState(this, { none: { value: null, name: "(default)" } });
},
async test(assert) {
await this.subject.expand();
const noneRow = this.subject.rowByIndex(0);
assert.strictEqual(noneRow.value(), null);
assert.strictEqual(noneRow.name(), "(default)");
},
});
componentTest("content is a basic array", {
template: hbs`
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
options=(hash
none="test.none"
)
}}
`,
beforeEach() {
I18n.translations[I18n.locale].js.test = { none: "(default)" };
setDefaultState(this, {
nameProperty: null,
valueProperty: null,
value: "foo",
content: ["foo", "bar", "baz"],
});
},
async test(assert) {
await this.subject.expand();
const noneRow = this.subject.rowByIndex(0);
assert.strictEqual(noneRow.value(), I18n.t("test.none"));
assert.strictEqual(noneRow.name(), I18n.t("test.none"));
assert.strictEqual(this.value, "foo");
await this.subject.selectRowByIndex(0);
assert.strictEqual(this.value, null);
},
});
componentTest("selected value can be 0", {
template: hbs`
{{single-select
value=value
content=content
nameProperty=nameProperty
valueProperty=valueProperty
onChange=onChange
}}
`,
beforeEach() {
setDefaultState(this, {
value: 1,
content: [
{ id: 0, name: "foo" },
{ id: 1, name: "bar" },
],
});
},
async test(assert) {
assert.strictEqual(this.subject.header().value(), "1");
await this.subject.expand();
await this.subject.selectRowByValue(0);
assert.strictEqual(this.subject.header().value(), "0");
},
});
componentTest("prevents propagating click event on header", {
template: hbs`
{{#d-button icon='times' action=onClick}}
{{single-select
options=(hash preventsClickPropagation=true)
value=value
content=content
}} }}
{{/d-button}} />
`, `);
beforeEach() { await this.subject.expand();
this.setProperties({ assert.ok(this.subject.filter().exists(), "it shows the filter");
onClick: () => this.set("value", "foo"),
content: DEFAULT_CONTENT,
value: DEFAULT_VALUE,
});
},
async test(assert) { const filter = this.subject.displayedContent()[1].name;
assert.strictEqual(this.value, DEFAULT_VALUE); await this.subject.fillInFilter(filter);
await this.subject.expand(); assert.strictEqual(
assert.strictEqual(this.value, DEFAULT_VALUE); this.subject.displayedContent()[0].name,
}, filter,
"it filters the list"
);
});
test("options.limitMatches", async function (assert) {
setDefaultState(this, { limitMatches: 1, filterable: true });
await render(hbs`
<SingleSelect
@value={{this.value}}
@content={{this.content}}
@nameProperty={{this.nameProperty}}
@valueProperty={{this.valueProperty}}
@onChange={{this.onChange}}
@options={{hash
limitMatches=this.limitMatches
filterable=this.filterable
}}
/>
`);
await this.subject.expand();
await this.subject.fillInFilter("ba");
assert.strictEqual(
this.subject.displayedContent().length,
1,
"it returns only 1 result"
);
});
test("valueAttribute (deprecated)", async function (assert) {
this.set("value", "normal");
const content = [
{ name: "Smallest", value: "smallest" },
{ name: "Smaller", value: "smaller" },
{ name: "Normal", value: "normal" },
{ name: "Larger", value: "larger" },
{ name: "Largest", value: "largest" },
];
this.set("content", content);
await render(hbs`
<SingleSelect
@value={{this.value}}
@content={{this.content}}
@valueAttribute="value"
/>
`);
await this.subject.expand();
assert.strictEqual(this.subject.selectedRow().value(), this.value);
});
test("none:string", async function (assert) {
I18n.translations[I18n.locale].js.test = { none: "(default)" };
setDefaultState(this, { value: 1 });
await render(hbs`
<SingleSelect
@value={{this.value}}
@content={{this.content}}
@nameProperty={{this.nameProperty}}
@valueProperty={{this.valueProperty}}
@onChange={{this.onChange}}
@options={{hash
none="test.none"
}}
/>
`);
await this.subject.expand();
const noneRow = this.subject.rowByIndex(0);
assert.strictEqual(noneRow.value(), null);
assert.strictEqual(noneRow.name(), I18n.t("test.none"));
});
test("none:object", async function (assert) {
setDefaultState(this, { none: { value: null, name: "(default)" } });
await render(hbs`
<SingleSelect
@value={{this.value}}
@content={{this.content}}
@nameProperty={{this.nameProperty}}
@valueProperty={{this.valueProperty}}
@onChange={{this.onChange}}
@options={{hash
none=this.none
}}
/>
`);
await this.subject.expand();
const noneRow = this.subject.rowByIndex(0);
assert.strictEqual(noneRow.value(), null);
assert.strictEqual(noneRow.name(), "(default)");
});
test("content is a basic array", async function (assert) {
I18n.translations[I18n.locale].js.test = { none: "(default)" };
setDefaultState(this, {
nameProperty: null,
valueProperty: null,
value: "foo",
content: ["foo", "bar", "baz"],
}); });
componentTest("labelProperty", { await render(hbs`
template: hbs` <SingleSelect
{{single-select @value={{this.value}}
labelProperty="foo" @content={{this.content}}
value=value @nameProperty={{this.nameProperty}}
content=content @valueProperty={{this.valueProperty}}
}} @onChange={{this.onChange}}
`, @options={{hash
none="test.none"
}}
/>
`);
beforeEach() { await this.subject.expand();
this.setProperties({
content: [{ id: 1, name: "john", foo: "JACKSON" }],
value: 1,
});
},
async test(assert) { const noneRow = this.subject.rowByIndex(0);
assert.strictEqual(this.subject.header().label(), "JACKSON"); assert.strictEqual(noneRow.value(), I18n.t("test.none"));
assert.strictEqual(noneRow.name(), I18n.t("test.none"));
assert.strictEqual(this.value, "foo");
await this.subject.expand(); await this.subject.selectRowByIndex(0);
const row = this.subject.rowByValue(1); assert.strictEqual(this.value, null);
});
assert.strictEqual(row.label(), "JACKSON"); test("selected value can be 0", async function (assert) {
}, setDefaultState(this, {
value: 1,
content: [
{ id: 0, name: "foo" },
{ id: 1, name: "bar" },
],
}); });
componentTest("titleProperty", { await render(hbs`
template: hbs` <SingleSelect
{{single-select @value={{this.value}}
titleProperty="foo" @content={{this.content}}
value=value @nameProperty={{this.nameProperty}}
content=content @valueProperty={{this.valueProperty}}
}} @onChange={{this.onChange}}
`, />
`);
beforeEach() { assert.strictEqual(this.subject.header().value(), "1");
this.setProperties({
content: [{ id: 1, name: "john", foo: "JACKSON" }],
value: 1,
});
},
async test(assert) { await this.subject.expand();
assert.strictEqual(this.subject.header().title(), "JACKSON"); await this.subject.selectRowByValue(0);
await this.subject.expand(); assert.strictEqual(this.subject.header().value(), "0");
});
const row = this.subject.rowByValue(1); test("prevents propagating click event on header", async function (assert) {
this.setProperties({
assert.strictEqual(row.title(), "JACKSON"); onClick: () => this.set("value", "foo"),
}, content: DEFAULT_CONTENT,
value: DEFAULT_VALUE,
}); });
componentTest("langProperty", { await render(hbs`
template: hbs`{{single-select langProperty="foo" value=value content=content}}`, <DButton @icon="times" @action={{this.onClick}}>
<SingleSelect
@value={{this.value}}
@content={{this.content}}
@options={{hash preventsClickPropagation=true}}
/>
</DButton>
`);
beforeEach() { assert.strictEqual(this.value, DEFAULT_VALUE);
this.setProperties({ await this.subject.expand();
content: [{ id: 1, name: "john", foo: "be" }], assert.strictEqual(this.value, DEFAULT_VALUE);
value: null, });
});
},
async test(assert) { test("labelProperty", async function (assert) {
assert.strictEqual( this.setProperties({
this.subject.header().el().querySelector(".selected-name").lang, content: [{ id: 1, name: "john", foo: "JACKSON" }],
"" value: 1,
);
await this.subject.expand();
const row = this.subject.rowByValue(1);
assert.strictEqual(row.el().lang, "be");
await this.subject.selectRowByValue(1);
assert.strictEqual(
this.subject.header().el().querySelector(".selected-name").lang,
"be"
);
},
}); });
componentTest("name", { await render(hbs`
template: hbs`{{single-select value=value content=content}}`, <SingleSelect
@labelProperty="foo"
@value={{this.value}}
@content={{this.content}}
/>
`);
beforeEach() { assert.strictEqual(this.subject.header().label(), "JACKSON");
this.setProperties({
content: [{ id: 1, name: "john" }],
value: null,
});
},
async test(assert) { await this.subject.expand();
assert.strictEqual(
this.subject.header().el().getAttribute("name"),
I18n.t("select_kit.select_to_filter")
);
await this.subject.expand(); const row = this.subject.rowByValue(1);
await this.subject.selectRowByValue(1);
assert.strictEqual( assert.strictEqual(row.label(), "JACKSON");
this.subject.header().el().getAttribute("name"), });
I18n.t("select_kit.filter_by", {
name: this.content.firstObject.name, test("titleProperty", async function (assert) {
}) this.setProperties({
); content: [{ id: 1, name: "john", foo: "JACKSON" }],
}, value: 1,
}); });
}
); await render(hbs`
<SingleSelect
@titleProperty="foo"
@value={{this.value}}
@content={{this.content}}
/>
`);
assert.strictEqual(this.subject.header().title(), "JACKSON");
await this.subject.expand();
const row = this.subject.rowByValue(1);
assert.strictEqual(row.title(), "JACKSON");
});
test("langProperty", async function (assert) {
this.setProperties({
content: [{ id: 1, name: "john", foo: "be" }],
value: null,
});
await render(
hbs`<SingleSelect @langProperty="foo" @value={{this.value}} @content={{this.content}} />`
);
assert.strictEqual(
this.subject.header().el().querySelector(".selected-name").lang,
""
);
await this.subject.expand();
const row = this.subject.rowByValue(1);
assert.strictEqual(row.el().lang, "be");
await this.subject.selectRowByValue(1);
assert.strictEqual(
this.subject.header().el().querySelector(".selected-name").lang,
"be"
);
});
test("name", async function (assert) {
this.setProperties({
content: [{ id: 1, name: "john" }],
value: null,
});
await render(
hbs`<SingleSelect @value={{this.value}} @content={{this.content}} />`
);
assert.strictEqual(
this.subject.header().el().getAttribute("name"),
I18n.t("select_kit.select_to_filter")
);
await this.subject.expand();
await this.subject.selectRowByValue(1);
assert.strictEqual(
this.subject.header().el().getAttribute("name"),
I18n.t("select_kit.filter_by", {
name: this.content.firstObject.name,
})
);
});
});

View File

@ -1,13 +1,10 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import I18n from "I18n"; import I18n from "I18n";
import Site from "discourse/models/site";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender from "discourse/tests/helpers/create-pretender"; import pretender, { response } from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
import { set } from "@ember/object";
function initTags(context) { function initTags(context) {
const categories = context.site.categoriesList; const categories = context.site.categoriesList;
@ -20,94 +17,70 @@ function initTags(context) {
}); });
} }
discourseModule( module("Integration | Component | select-kit/tag-drop", function (hooks) {
"Integration | Component | select-kit/tag-drop", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
const site = Site.current(); this.site.set("top_tags", ["jeff", "neil", "arpit", "régis"]);
set(site, "top_tags", ["jeff", "neil", "arpit", "régis"]);
const response = (object) => { pretender.get("/tags/filter/search", (params) => {
return [200, { "Content-Type": "application/json" }, object]; if (params.queryParams.q === "dav") {
}; return response({
results: [{ id: "David", name: "David", count: 2, pm_count: 0 }],
pretender.get("/tags/filter/search", (params) => { });
if (params.queryParams.q === "dav") { }
return response({
results: [{ id: "David", name: "David", count: 2, pm_count: 0 }],
});
}
});
}); });
});
componentTest("default", { test("default", async function (assert) {
template: hbs` initTags(this);
{{tag-drop
currentCategory=currentCategory
tagId=tagId
options=(hash
tagId=tagId
)
}}
`,
beforeEach() { await render(hbs`
initTags(this); <TagDrop
}, @currentCategory={{this.currentCategory}}
@tagId={{this.tagId}}
@options={{hash
tagId=this.tagId
}}
/>
`);
async test(assert) { await this.subject.expand();
await this.subject.expand();
assert.ok(true); const content = this.subject.displayedContent();
// const row = this.subject.rowByValue(this.category.id);
// assert.ok(
// exists(row.el().find(".category-desc")),
// "it shows category description for newcomers"
// );
const content = this.subject.displayedContent(); assert.strictEqual(
content[0].name,
I18n.t("tagging.selector_no_tags"),
"it has the translated label for no-tags"
);
assert.strictEqual(
content[1].name,
I18n.t("tagging.selector_all_tags"),
"it has the correct label for all-tags"
);
assert.strictEqual( await this.subject.fillInFilter("dav");
content[0].name,
I18n.t("tagging.selector_no_tags"),
"it has the translated label for no-tags"
);
assert.strictEqual(
content[1].name,
I18n.t("tagging.selector_all_tags"),
"it has the correct label for all-tags"
);
await this.subject.fillInFilter("dav"); assert.strictEqual(
this.subject.rows()[0].textContent.trim(),
"David",
"it has no tag count when filtering in a category context"
);
});
assert.strictEqual( test("default global (no category)", async function (assert) {
this.subject.rows()[0].textContent.trim(), await render(hbs`<TagDrop />`);
"David",
"it has no tag count when filtering in a category context"
);
},
});
componentTest("default global (no category)", { await this.subject.expand();
template: hbs`{{tag-drop}}`, await this.subject.fillInFilter("dav");
async test(assert) { assert.strictEqual(
await this.subject.expand(); this.subject.rows()[0].textContent.trim(),
"David x2",
assert.ok(true); "it has the tag count"
);
await this.subject.fillInFilter("dav"); });
});
assert.strictEqual(
this.subject.rows()[0].textContent.trim(),
"David x2",
"it has the tag count"
);
},
});
}
);

View File

@ -1,12 +1,9 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import I18n from "I18n"; import I18n from "I18n";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { import { query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -28,7 +25,7 @@ const buildTopic = function (opts) {
const originalTranslation = const originalTranslation =
I18n.translations.en.js.topic.notifications.tracking_pm.title; I18n.translations.en.js.topic.notifications.tracking_pm.title;
discourseModule( module(
"Integration | Component | select-kit/topic-notifications-button", "Integration | Component | select-kit/topic-notifications-button",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@ -38,247 +35,192 @@ discourseModule(
originalTranslation; originalTranslation;
}); });
componentTest("the header has a localized title", { test("the header has a localized title", async function (assert) {
template: hbs` this.set("topic", buildTopic({ level: 1 }));
{{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.set("topic", buildTopic({ level: 1 })); <TopicNotificationsButton
}, @notificationLevel={{this.topic.details.notification_level}}
@topic={{this.topic}}
/>
`);
async test(assert) { assert.strictEqual(
assert.strictEqual( selectKit().header().label(),
selectKit().header().label(), "Normal",
"Normal", "it has the correct label"
"it has the correct label" );
);
await this.set("topic", buildTopic({ level: 2 })); this.set("topic", buildTopic({ level: 2 }));
assert.strictEqual( assert.strictEqual(
selectKit().header().label(), selectKit().header().label(),
"Tracking", "Tracking",
"it correctly changes the label" "it correctly changes the label"
); );
},
}); });
componentTest("the header has a localized title", { test("the header has a localized title", async function (assert) {
template: hbs` I18n.translations.en.js.topic.notifications.tracking_pm.title = `${originalTranslation} PM`;
{{topic-notifications-button this.set("topic", buildTopic({ level: 2, archetype: "private_message" }));
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
I18n.translations.en.js.topic.notifications.tracking_pm.title = `${originalTranslation} PM`; <TopicNotificationsButton
this.set( @notificationLevel={{this.topic.details.notification_level}}
"topic", @topic={{this.topic}}
buildTopic({ level: 2, archetype: "private_message" }) />
); `);
},
test(assert) { assert.strictEqual(
assert.strictEqual( selectKit().header().label(),
selectKit().header().label(), `${originalTranslation} PM`,
`${originalTranslation} PM`, "it has the correct label for PMs"
"it has the correct label for PMs" );
);
},
}); });
componentTest("notification reason text - user mailing list mode", { test("notification reason text - user mailing list mode", async function (assert) {
template: hbs` this.currentUser.set("mailing_list_mode", true);
{{topic-notifications-button this.set("topic", buildTopic({ level: 2 }));
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.currentUser.set("mailing_list_mode", true); <TopicNotificationsButton
this.set("topic", buildTopic({ level: 2 })); @notificationLevel={{this.topic.details.notification_level}}
}, @topic={{this.topic}}
/>
`);
test(assert) { assert.strictEqual(
assert.strictEqual( query(".topic-notifications-button .text").innerText,
queryAll(".topic-notifications-button .text").text(), I18n.t("topic.notifications.reasons.mailing_list_mode"),
I18n.t("topic.notifications.reasons.mailing_list_mode"), "mailing_list_mode enabled for the user shows unique text"
"mailing_list_mode enabled for the user shows unique text" );
);
},
}); });
componentTest("notification reason text - bad notification reason", { test("notification reason text - bad notification reason", async function (assert) {
template: hbs` this.set("topic", buildTopic({ level: 2 }));
{{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.set("topic", buildTopic({ level: 2 })); <TopicNotificationsButton
}, @notificationLevel={{this.topic.details.notification_level}}
@topic={{this.topic}}
/>
`);
test(assert) { this.set("topic", buildTopic({ level: 3, reason: 999 }));
this.set("topic", buildTopic({ level: 3, reason: 999 }));
assert.strictEqual( assert.strictEqual(
queryAll(".topic-notifications-button .text").text(), query(".topic-notifications-button .text").innerText,
I18n.t("topic.notifications.reasons.3"), I18n.t("topic.notifications.reasons.3"),
"fallback to regular level translation if reason does not exist" "fallback to regular level translation if reason does not exist"
); );
},
}); });
componentTest("notification reason text - user tracking category", { test("notification reason text - user tracking category", async function (assert) {
template: hbs` this.currentUser.set("tracked_category_ids", [88]);
{{topic-notifications-button this.set("topic", buildTopic({ level: 2, reason: 8, category_id: 88 }));
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.currentUser.set("tracked_category_ids", [88]); <TopicNotificationsButton
this.set("topic", buildTopic({ level: 2, reason: 8, category_id: 88 })); @notificationLevel={{this.topic.details.notification_level}}
}, @topic={{this.topic}}
/>
`);
test(assert) { assert.strictEqual(
assert.strictEqual( query(".topic-notifications-button .text").innerText,
queryAll(".topic-notifications-button .text").text(), I18n.t("topic.notifications.reasons.2_8"),
I18n.t("topic.notifications.reasons.2_8"), "use 2_8 notification if user is still tracking category"
"use 2_8 notification if user is still tracking category" );
);
},
}); });
componentTest( test("notification reason text - user no longer tracking category", async function (assert) {
"notification reason text - user no longer tracking category", this.currentUser.set("tracked_category_ids", []);
{ this.set("topic", buildTopic({ level: 2, reason: 8, category_id: 88 }));
template: hbs`
{{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.currentUser.set("tracked_category_ids", []); <TopicNotificationsButton
this.set( @notificationLevel={{this.topic.details.notification_level}}
"topic", @topic={{this.topic}}
buildTopic({ level: 2, reason: 8, category_id: 88 }) />
); `);
},
test(assert) { assert.strictEqual(
assert.strictEqual( query(".topic-notifications-button .text").innerText,
queryAll(".topic-notifications-button .text").text(), I18n.t("topic.notifications.reasons.2_8_stale"),
I18n.t("topic.notifications.reasons.2_8_stale"), "use _stale notification if user is no longer tracking category"
"use _stale notification if user is no longer tracking category" );
);
},
}
);
componentTest("notification reason text - user watching category", {
template: hbs`
{{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() {
this.currentUser.set("watched_category_ids", [88]);
this.set("topic", buildTopic({ level: 3, reason: 6, category_id: 88 }));
},
test(assert) {
assert.strictEqual(
queryAll(".topic-notifications-button .text").text(),
I18n.t("topic.notifications.reasons.3_6"),
"use 3_6 notification if user is still watching category"
);
},
}); });
componentTest( test("notification reason text - user watching category", async function (assert) {
"notification reason text - user no longer watching category", this.currentUser.set("watched_category_ids", [88]);
{ this.set("topic", buildTopic({ level: 3, reason: 6, category_id: 88 }));
template: hbs`
{{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.currentUser.set("watched_category_ids", []); <TopicNotificationsButton
this.set( @notificationLevel={{this.topic.details.notification_level}}
"topic", @topic={{this.topic}}
buildTopic({ level: 3, reason: 6, category_id: 88 }) />
); `);
},
test(assert) { assert.strictEqual(
assert.strictEqual( query(".topic-notifications-button .text").innerText,
queryAll(".topic-notifications-button .text").text(), I18n.t("topic.notifications.reasons.3_6"),
I18n.t("topic.notifications.reasons.3_6_stale"), "use 3_6 notification if user is still watching category"
"use _stale notification if user is no longer watching category" );
);
},
}
);
componentTest("notification reason text - user watching tag", {
template: hbs`
{{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() {
this.currentUser.set("watched_tags", ["test"]);
this.set("topic", buildTopic({ level: 3, reason: 10, tags: ["test"] }));
},
test(assert) {
assert.strictEqual(
queryAll(".topic-notifications-button .text").text(),
I18n.t("topic.notifications.reasons.3_10"),
"use 3_10 notification if user is still watching tag"
);
},
}); });
componentTest("notification reason text - user no longer watching tag", { test("notification reason text - user no longer watching category", async function (assert) {
template: hbs` this.currentUser.set("watched_category_ids", []);
{{topic-notifications-button this.set("topic", buildTopic({ level: 3, reason: 6, category_id: 88 }));
notificationLevel=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.currentUser.set("watched_tags", []); <TopicNotificationsButton
this.set("topic", buildTopic({ level: 3, reason: 10, tags: ["test"] })); @notificationLevel={{this.topic.details.notification_level}}
}, @topic={{this.topic}}
/>
`);
test(assert) { assert.strictEqual(
assert.strictEqual( query(".topic-notifications-button .text").innerText,
queryAll(".topic-notifications-button .text").text(), I18n.t("topic.notifications.reasons.3_6_stale"),
I18n.t("topic.notifications.reasons.3_10_stale"), "use _stale notification if user is no longer watching category"
"use _stale notification if user is no longer watching tag" );
); });
},
test("notification reason text - user watching tag", async function (assert) {
this.currentUser.set("watched_tags", ["test"]);
this.set("topic", buildTopic({ level: 3, reason: 10, tags: ["test"] }));
await render(hbs`
<TopicNotificationsButton
@notificationLevel={{this.topic.details.notification_level}}
@topic={{this.topic}}
/>
`);
assert.strictEqual(
query(".topic-notifications-button .text").innerText,
I18n.t("topic.notifications.reasons.3_10"),
"use 3_10 notification if user is still watching tag"
);
});
test("notification reason text - user no longer watching tag", async function (assert) {
this.currentUser.set("watched_tags", []);
this.set("topic", buildTopic({ level: 3, reason: 10, tags: ["test"] }));
await render(hbs`
<TopicNotificationsButton
@notificationLevel={{this.topic.details.notification_level}}
@topic={{this.topic}}
/>
`);
assert.strictEqual(
query(".topic-notifications-button .text").innerText,
I18n.t("topic.notifications.reasons.3_10_stale"),
"use _stale notification if user is no longer watching tag"
);
}); });
} }
); );

View File

@ -1,9 +1,8 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import I18n from "I18n"; import I18n from "I18n";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -29,76 +28,69 @@ function getTranslations(type = "") {
}); });
} }
discourseModule( module(
"Integration | Component | select-kit/topic-notifications-options", "Integration | Component | select-kit/topic-notifications-options",
function (hooks) { function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("regular topic notification level descriptions", { test("regular topic notification level descriptions", async function (assert) {
template: hbs` this.set("topic", buildTopic("regular"));
{{topic-notifications-options
value=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.set("topic", buildTopic("regular")); <TopicNotificationsOptions
}, @value={{this.topic.details.notification_level}}
@topic={{this.topic}}
/>
`);
async test(assert) { await selectKit().expand();
await selectKit().expand();
const uiTexts = extractDescriptions(selectKit().rows()); const uiTexts = extractDescriptions(selectKit().rows());
const descriptions = getTranslations(); const descriptions = getTranslations();
assert.strictEqual(
uiTexts.length,
descriptions.length,
"it has the correct copy"
);
uiTexts.forEach((text, index) => {
assert.strictEqual( assert.strictEqual(
uiTexts.length, text.trim(),
descriptions.length, descriptions[index].trim(),
"it has the correct copy" "it has the correct copy"
); );
uiTexts.forEach((text, index) => { });
assert.strictEqual(
text.trim(),
descriptions[index].trim(),
"it has the correct copy"
);
});
},
}); });
componentTest("PM topic notification level descriptions", { test("PM topic notification level descriptions", async function (assert) {
template: hbs` this.set("topic", buildTopic("private_message"));
{{topic-notifications-options
value=topic.details.notification_level
topic=topic
}}
`,
beforeEach() { await render(hbs`
this.set("topic", buildTopic("private_message")); <TopicNotificationsOptions
}, @value={{this.topic.details.notification_level}}
@topic={{this.topic}}
/>
`);
async test(assert) { await selectKit().expand();
await selectKit().expand();
const uiTexts = extractDescriptions(selectKit().rows()); const uiTexts = extractDescriptions(selectKit().rows());
const descriptions = getTranslations("_pm"); const descriptions = getTranslations("_pm");
assert.strictEqual(
uiTexts.length,
descriptions.length,
"it has the correct copy"
);
uiTexts.forEach((text, index) => {
assert.strictEqual( assert.strictEqual(
uiTexts.length, text.trim(),
descriptions.length, descriptions[index].trim(),
"it has the correct copy" "it has the correct copy"
); );
});
uiTexts.forEach((text, index) => {
assert.strictEqual(
text.trim(),
descriptions[index].trim(),
"it has the correct copy"
);
});
},
}); });
} }
); );

View File

@ -1,43 +1,31 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
discourseModule( module("Integration | Component | select-kit/user-chooser", function (hooks) {
"Integration | Component | select-kit/user-chooser", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("displays usernames", { test("displays usernames", async function (assert) {
template: hbs`{{user-chooser value=value}}`, this.set("value", ["bob", "martin"]);
beforeEach() { await render(hbs`<UserChooser @value={{this.value}} />`);
this.set("value", ["bob", "martin"]);
},
async test(assert) { assert.strictEqual(this.subject.header().name(), "bob,martin");
assert.strictEqual(this.subject.header().name(), "bob,martin"); });
},
});
componentTest("can remove a username", { test("can remove a username", async function (assert) {
template: hbs`{{user-chooser value=value}}`, this.set("value", ["bob", "martin"]);
beforeEach() { await render(hbs`<UserChooser @value={{this.value}} />`);
this.set("value", ["bob", "martin"]);
},
async test(assert) { await this.subject.expand();
await this.subject.expand(); await this.subject.deselectItemByValue("bob");
await this.subject.deselectItemByValue("bob"); assert.strictEqual(this.subject.header().name(), "martin");
assert.strictEqual(this.subject.header().name(), "martin"); });
}, });
});
}
);

View File

@ -1,3 +1,5 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { import {
blur, blur,
click, click,
@ -5,57 +7,45 @@ import {
render, render,
triggerKeyEvent, triggerKeyEvent,
} from "@ember/test-helpers"; } from "@ember/test-helpers";
import componentTest, { import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import {
count,
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { test } from "qunit";
discourseModule("Integration | Component | simple-list", function (hooks) { module("Integration | Component | simple-list", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("adding a value", { test("adding a value", async function (assert) {
template: hbs`{{simple-list values=values}}`, this.set("values", "vinkas\nosama");
beforeEach() { await render(hbs`<SimpleList @values={{this.values}} />`);
this.set("values", "vinkas\nosama");
},
async test(assert) { assert.ok(
assert.ok( exists(".add-value-btn[disabled]"),
exists(".add-value-btn[disabled]"), "while loading the + button is disabled"
"while loading the + button is disabled" );
);
await fillIn(".add-value-input", "penar"); await fillIn(".add-value-input", "penar");
await click(".add-value-btn"); await click(".add-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.ok( assert.strictEqual(
query(".values .value[data-index='2'] .value-input").value === "penar", query(".values .value[data-index='2'] .value-input").value,
"it sets the correct value for added item" "penar",
); "it sets the correct value for added item"
);
await fillIn(".add-value-input", "eviltrout"); await fillIn(".add-value-input", "eviltrout");
await triggerKeyEvent(".add-value-input", "keydown", 13); // enter await triggerKeyEvent(".add-value-input", "keydown", 13); // enter
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
4, 4,
"it adds the value when keying Enter" "it adds the value when keying Enter"
); );
},
}); });
test("changing a value", async function (assert) { test("changing a value", async function (assert) {
@ -67,7 +57,9 @@ discourseModule("Integration | Component | simple-list", function (hooks) {
done(); done();
}); });
await render(hbs`{{simple-list values=values onChange=onChange}}`); await render(
hbs`<SimpleList @values={{this.values}} @onChange={{this.onChange}} />`
);
await fillIn(".values .value[data-index='1'] .value-input", "jarek"); await fillIn(".values .value[data-index='1'] .value-input", "jarek");
await blur(".values .value[data-index='1'] .value-input"); await blur(".values .value[data-index='1'] .value-input");
@ -78,51 +70,46 @@ discourseModule("Integration | Component | simple-list", function (hooks) {
); );
}); });
componentTest("removing a value", { test("removing a value", async function (assert) {
template: hbs`{{simple-list values=values}}`, this.set("values", "vinkas\nosama");
beforeEach() { await render(hbs`<SimpleList @values={{this.values}} />`);
this.set("values", "vinkas\nosama");
},
async test(assert) { await click(".values .value[data-index='0'] .remove-value-btn");
await click(".values .value[data-index='0'] .remove-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
1, 1,
"it removes the value from the list of values" "it removes the value from the list of values"
); );
assert.ok( assert.strictEqual(
query(".values .value[data-index='0'] .value-input").value === "osama", query(".values .value[data-index='0'] .value-input").value,
"it removes the correct value" "osama",
); "it removes the correct value"
}, );
}); });
componentTest("delimiter support", { test("delimiter support", async function (assert) {
template: hbs`{{simple-list values=values inputDelimiter='|'}}`, this.set("values", "vinkas|osama");
beforeEach() { await render(
this.set("values", "vinkas|osama"); hbs`<SimpleList @values={{this.values}} @inputDelimiter="|" />`
}, );
async test(assert) { await fillIn(".add-value-input", "eviltrout");
await fillIn(".add-value-input", "eviltrout"); await click(".add-value-btn");
await click(".add-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.ok( assert.strictEqual(
query(".values .value[data-index='2'] .value-input").value === query(".values .value[data-index='2'] .value-input").value,
"eviltrout", "eviltrout",
"it adds the correct value" "it adds the correct value"
); );
},
}); });
}); });

View File

@ -1,16 +1,11 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { import { count, exists } from "discourse/tests/helpers/qunit-helpers";
count,
discourseModule,
exists,
} from "discourse/tests/helpers/qunit-helpers";
import pretender from "discourse/tests/helpers/create-pretender"; import pretender from "discourse/tests/helpers/create-pretender";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { click } from "@ember/test-helpers";
discourseModule("Integration | Component | site-header", function (hooks) { module("Integration | Component | site-header", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
@ -18,43 +13,40 @@ discourseModule("Integration | Component | site-header", function (hooks) {
this.currentUser.set("read_first_notification", false); this.currentUser.set("read_first_notification", false);
}); });
componentTest("first notification mask", { test("first notification mask", async function (assert) {
template: hbs`{{site-header}}`, await render(hbs`<SiteHeader />`);
async test(assert) { assert.strictEqual(
assert.strictEqual( count(".ring-backdrop"),
count(".ring-backdrop"), 1,
1, "there is the first notification mask"
"there is the first notification mask" );
);
// Click anywhere // Click anywhere
await click("header.d-header"); await click("header.d-header");
assert.ok( assert.ok(
!exists(".ring-backdrop"), !exists(".ring-backdrop"),
"it hides the first notification mask" "it hides the first notification mask"
); );
},
}); });
componentTest("do not call authenticated endpoints as anonymous", { test("do not call authenticated endpoints as anonymous", async function (assert) {
template: hbs`{{site-header}}`, this.owner.unregister("current-user:main");
anonymous: true,
async test(assert) { await render(hbs`<SiteHeader />`);
assert.ok(
!exists(".ring-backdrop"),
"there is no first notification mask for anonymous users"
);
pretender.get("/notifications", () => { assert.ok(
assert.ok(false, "it should not try to refresh notifications"); !exists(".ring-backdrop"),
return [403, { "Content-Type": "application/json" }, {}]; "there is no first notification mask for anonymous users"
}); );
// Click anywhere pretender.get("/notifications", () => {
await click("header.d-header"); assert.ok(false, "it should not try to refresh notifications");
}, return [403, { "Content-Type": "application/json" }, {}];
});
// Click anywhere
await click("header.d-header");
}); });
}); });

View File

@ -0,0 +1,21 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | site-setting", function (hooks) {
setupRenderingTest(hooks);
test("displays host-list setting value", async function (assert) {
this.set("setting", {
setting: "blocked_onebox_domains",
value: "a.com|b.com",
type: "host_list",
});
await render(hbs`<SiteSetting @setting={{this.setting}} />`);
assert.strictEqual(query(".formatted-selection").innerText, "a.com, b.com");
});
});

View File

@ -1,82 +1,62 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { count, exists } from "discourse/tests/helpers/qunit-helpers";
count,
discourseModule,
exists,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | slow-mode-info", function (hooks) { module("Integration | Component | slow-mode-info", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("doesn't render if the topic is closed", { test("doesn't render if the topic is closed", async function (assert) {
template: hbs`{{slow-mode-info topic=topic}}`, this.set("topic", { slow_mode_seconds: 3600, closed: true });
beforeEach() { await render(hbs`<SlowModeInfo @topic={{this.topic}} />`);
this.set("topic", { slow_mode_seconds: 3600, closed: true });
},
test(assert) { assert.ok(!exists(".slow-mode-heading"), "it doesn't render the notice");
assert.ok(!exists(".slow-mode-heading"), "it doesn't render the notice");
},
}); });
componentTest("doesn't render if the slow mode is disabled", { test("doesn't render if the slow mode is disabled", async function (assert) {
template: hbs`{{slow-mode-info topic=topic}}`, this.set("topic", { slow_mode_seconds: 0, closed: false });
beforeEach() { await render(hbs`<SlowModeInfo @topic={{this.topic}} />`);
this.set("topic", { slow_mode_seconds: 0, closed: false });
},
test(assert) { assert.ok(!exists(".slow-mode-heading"), "it doesn't render the notice");
assert.ok(!exists(".slow-mode-heading"), "it doesn't render the notice");
},
}); });
componentTest("renders if slow mode is enabled", { test("renders if slow mode is enabled", async function (assert) {
template: hbs`{{slow-mode-info topic=topic}}`, this.set("topic", { slow_mode_seconds: 3600, closed: false });
beforeEach() { await render(hbs`<SlowModeInfo @topic={{this.topic}} />`);
this.set("topic", { slow_mode_seconds: 3600, closed: false });
},
test(assert) { assert.strictEqual(count(".slow-mode-heading"), 1);
assert.strictEqual(count(".slow-mode-heading"), 1);
},
}); });
componentTest("staff and TL4 users can disable slow mode", { test("staff and TL4 users can disable slow mode", async function (assert) {
template: hbs`{{slow-mode-info topic=topic user=user}}`, this.setProperties({
topic: { slow_mode_seconds: 3600, closed: false },
user: { canManageTopic: true },
});
beforeEach() { await render(
this.setProperties({ hbs`<SlowModeInfo @topic={{this.topic}} @user={{this.user}} />`
topic: { slow_mode_seconds: 3600, closed: false }, );
user: { canManageTopic: true },
});
},
test(assert) { assert.strictEqual(count(".slow-mode-remove"), 1);
assert.strictEqual(count(".slow-mode-remove"), 1);
},
}); });
componentTest("regular users can't disable slow mode", { test("regular users can't disable slow mode", async function (assert) {
template: hbs`{{slow-mode-info topic=topic user=user}}`, this.setProperties({
topic: { slow_mode_seconds: 3600, closed: false },
user: { canManageTopic: false },
});
beforeEach() { await render(
this.setProperties({ hbs`<SlowModeInfo @topic={{this.topic}} @user={{this.user}} />`
topic: { slow_mode_seconds: 3600, closed: false }, );
user: { canManageTopic: false },
});
},
test(assert) { assert.ok(
assert.ok( !exists(".slow-mode-remove"),
!exists(".slow-mode-remove"), "it doesn't let you disable slow mode"
"it doesn't let you disable slow mode" );
);
},
}); });
}); });

View File

@ -0,0 +1,35 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import {
count,
exists,
publishToMessageBus,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import { later } from "@ember/runloop";
module("Integration | Component | software-update-prompt", function (hooks) {
setupRenderingTest(hooks);
test("software-update-prompt gets correct CSS class after messageBus message", async function (assert) {
await render(hbs`{{software-update-prompt}}`);
assert.ok(
!exists("div.software-update-prompt"),
"it does not have the class to show the prompt"
);
publishToMessageBus("/global/asset-version", "somenewversion");
const done = assert.async();
later(() => {
assert.strictEqual(
count("div.software-update-prompt.require-software-refresh"),
1,
"it does have the class to show the prompt"
);
done();
}, 10);
});
});

View File

@ -1,102 +1,84 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { fillIn, render } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n";
import { fillIn } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import sinon from "sinon"; import sinon from "sinon";
import I18n from "I18n";
discourseModule("Integration | Component | text-field", function (hooks) { module("Integration | Component | text-field", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("renders correctly with no properties set", { test("renders correctly with no properties set", async function (assert) {
template: hbs`{{text-field}}`, await render(hbs`<TextField />`);
test(assert) { assert.ok(exists("input[type=text]"));
assert.ok(exists("input[type=text]"));
},
}); });
componentTest("support a placeholder", { test("support a placeholder", async function (assert) {
template: hbs`{{text-field placeholderKey="placeholder.i18n.key"}}`, sinon.stub(I18n, "t").returnsArg(0);
beforeEach() { await render(hbs`<TextField @placeholderKey="placeholder.i18n.key" />`);
sinon.stub(I18n, "t").returnsArg(0);
},
test(assert) { assert.ok(exists("input[type=text]"));
assert.ok(exists("input[type=text]")); assert.strictEqual(query("input").placeholder, "placeholder.i18n.key");
assert.strictEqual(
queryAll("input").prop("placeholder"),
"placeholder.i18n.key"
);
},
}); });
componentTest("sets the dir attribute to ltr for Hebrew text", { test("sets the dir attribute to ltr for Hebrew text", async function (assert) {
template: hbs`{{text-field value='זהו שם עברי עם מקום עברי'}}`, this.siteSettings.support_mixed_text_direction = true;
beforeEach() {
this.siteSettings.support_mixed_text_direction = true;
},
test(assert) { await render(hbs`<TextField @value="זהו שם עברי עם מקום עברי" />`);
assert.strictEqual(queryAll("input").attr("dir"), "rtl");
}, assert.strictEqual(query("input").getAttribute("dir"), "rtl");
}); });
componentTest("sets the dir attribute to ltr for English text", { test("sets the dir attribute to ltr for English text", async function (assert) {
template: hbs`{{text-field value='This is a ltr title'}}`, this.siteSettings.support_mixed_text_direction = true;
beforeEach() {
this.siteSettings.support_mixed_text_direction = true;
},
test(assert) { await render(hbs`<TextField @value="This is a ltr title" />`);
assert.strictEqual(queryAll("input").attr("dir"), "ltr");
}, assert.strictEqual(query("input").getAttribute("dir"), "ltr");
}); });
componentTest("supports onChange", { test("supports onChange", async function (assert) {
template: hbs`{{text-field class="tf-test" value=value onChange=changed}}`, this.called = false;
beforeEach() { this.newValue = null;
this.called = false; this.set("value", "hello");
this.newValue = null; this.set("changed", (v) => {
this.set("value", "hello"); this.newValue = v;
this.set("changed", (v) => { this.called = true;
this.newValue = v; });
this.called = true;
}); await render(
}, hbs`<TextField class="tf-test" @value={{this.value}} @onChange={{this.changed}} />`
async test(assert) { );
await fillIn(".tf-test", "hello");
assert.ok(!this.called); await fillIn(".tf-test", "hello");
await fillIn(".tf-test", "new text"); assert.ok(!this.called);
assert.ok(this.called);
assert.strictEqual(this.newValue, "new text"); await fillIn(".tf-test", "new text");
}, assert.ok(this.called);
assert.strictEqual(this.newValue, "new text");
}); });
componentTest("supports onChangeImmediate", { test("supports onChangeImmediate", async function (assert) {
template: hbs`{{text-field class="tf-test" value=value onChangeImmediate=changed}}`, this.called = false;
beforeEach() { this.newValue = null;
this.called = false; this.set("value", "old");
this.newValue = null; this.set("changed", (v) => {
this.set("value", "old"); this.newValue = v;
this.set("changed", (v) => { this.called = true;
this.newValue = v; });
this.called = true;
}); await render(
}, hbs`<TextField class="tf-test" @value={{this.value}} @onChangeImmediate={{this.changed}} />`
async test(assert) { );
await fillIn(".tf-test", "old");
assert.ok(!this.called); await fillIn(".tf-test", "old");
await fillIn(".tf-test", "no longer old"); assert.ok(!this.called);
assert.ok(this.called);
assert.strictEqual(this.newValue, "no longer old"); await fillIn(".tf-test", "no longer old");
}, assert.ok(this.called);
assert.strictEqual(this.newValue, "no longer old");
}); });
}); });

View File

@ -1,104 +1,87 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import I18n from "I18n"; import I18n from "I18n";
import Theme from "admin/models/theme"; import Theme from "admin/models/theme";
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import {
count,
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | themes-list-item", function (hooks) { module("Integration | Component | themes-list-item", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("default theme", {
template: hbs`{{themes-list-item theme=theme}}`,
beforeEach() {
this.set("theme", Theme.create({ name: "Test", default: true }));
},
test(assert) { test("default theme", async function (assert) {
assert.expect(1); this.set("theme", Theme.create({ name: "Test", default: true }));
assert.strictEqual(count(".d-icon-check"), 1, "shows default theme icon");
}, await render(hbs`<ThemesListItem @theme={{this.theme}} />`);
assert.expect(1);
assert.strictEqual(count(".d-icon-check"), 1, "shows default theme icon");
}); });
componentTest("pending updates", { test("pending updates", async function (assert) {
template: hbs`{{themes-list-item theme=theme}}`, this.set(
beforeEach() { "theme",
this.set( Theme.create({ name: "Test", remote_theme: { commits_behind: 6 } })
"theme", );
Theme.create({ name: "Test", remote_theme: { commits_behind: 6 } })
);
},
test(assert) { await render(hbs`<ThemesListItem @theme={{this.theme}} />`);
assert.expect(1);
assert.strictEqual(count(".d-icon-sync"), 1, "shows pending update icon"); assert.expect(1);
}, assert.strictEqual(count(".d-icon-sync"), 1, "shows pending update icon");
}); });
componentTest("broken theme", { test("broken theme", async function (assert) {
template: hbs`{{themes-list-item theme=theme}}`, this.set(
beforeEach() { "theme",
this.set( Theme.create({
"theme", name: "Test",
Theme.create({ theme_fields: [{ name: "scss", type_id: 1, error: "something" }],
name: "Test", })
theme_fields: [{ name: "scss", type_id: 1, error: "something" }], );
})
);
},
test(assert) { await render(hbs`<ThemesListItem @theme={{this.theme}} />`);
assert.expect(1);
assert.strictEqual( assert.expect(1);
count(".d-icon-exclamation-circle"), assert.strictEqual(
1, count(".d-icon-exclamation-circle"),
"shows broken theme icon" 1,
); "shows broken theme icon"
}, );
}); });
componentTest("with children", { test("with children", async function (assert) {
template: hbs`{{themes-list-item theme=theme}}`, this.childrenList = [1, 2, 3, 4, 5].map((num) =>
Theme.create({ name: `Child ${num}`, component: true })
);
beforeEach() { this.set(
this.childrenList = [1, 2, 3, 4, 5].map((num) => "theme",
Theme.create({ name: `Child ${num}`, component: true }) Theme.create({
); name: "Test",
childThemes: this.childrenList,
default: true,
})
);
this.set( await render(hbs`<ThemesListItem @theme={{this.theme}} />`);
"theme",
Theme.create({
name: "Test",
childThemes: this.childrenList,
default: true,
})
);
},
test(assert) { assert.expect(2);
assert.expect(2); assert.deepEqual(
assert.deepEqual( query(".components")
queryAll(".components") .innerText.trim()
.text() .split(",")
.trim() .map((n) => n.trim())
.split(",") .join(","),
.map((n) => n.trim()) this.childrenList
.join(","), .splice(0, 4)
this.childrenList .map((theme) => theme.get("name"))
.splice(0, 4) .join(","),
.map((theme) => theme.get("name")) "lists the first 4 children"
.join(","), );
"lists the first 4 children" assert.deepEqual(
); query(".others-count").innerText.trim(),
assert.deepEqual( I18n.t("admin.customize.theme.and_x_more", { count: 1 }),
queryAll(".others-count").text().trim(), "shows count of remaining children"
I18n.t("admin.customize.theme.and_x_more", { count: 1 }), );
"shows count of remaining children"
);
},
}); });
}); });

View File

@ -1,17 +1,15 @@
import Theme, { COMPONENTS, THEMES } from "admin/models/theme"; import { module, test } from "qunit";
import I18n from "I18n"; import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import componentTest, { import { click, fillIn, render } from "@ember/test-helpers";
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { import {
count, count,
discourseModule,
exists, exists,
query, query,
queryAll, queryAll,
} from "discourse/tests/helpers/qunit-helpers"; } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { click, fillIn } from "@ember/test-helpers"; import Theme, { COMPONENTS, THEMES } from "admin/models/theme";
import I18n from "I18n";
function createThemes(itemsCount, customAttributesCallback) { function createThemes(itemsCount, customAttributesCallback) {
return [...Array(itemsCount)].map((_, i) => { return [...Array(itemsCount)].map((_, i) => {
@ -23,273 +21,254 @@ function createThemes(itemsCount, customAttributesCallback) {
}); });
} }
discourseModule("Integration | Component | themes-list", function (hooks) { module("Integration | Component | themes-list", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("current tab is themes", {
template: hbs`{{themes-list themes=themes components=components currentTab=currentTab}}`,
beforeEach() {
this.themes = createThemes(5);
this.components = createThemes(5, (n) => {
return {
name: `Child ${n}`,
component: true,
parentThemes: [this.themes[n - 1]],
parent_themes: [1, 2, 3, 4, 5],
};
});
this.setProperties({
themes: this.themes,
components: this.components,
currentTab: THEMES,
});
},
test(assert) { test("current tab is themes", async function (assert) {
assert.strictEqual( this.themes = createThemes(5);
queryAll(".themes-tab").hasClass("active"), this.components = createThemes(5, (n) => {
true, return {
"themes tab is active" name: `Child ${n}`,
); component: true,
assert.strictEqual( parentThemes: [this.themes[n - 1]],
queryAll(".components-tab").hasClass("active"), parent_themes: [1, 2, 3, 4, 5],
false, };
"components tab is not active" });
); this.setProperties({
themes: this.themes,
components: this.components,
currentTab: THEMES,
});
assert.strictEqual( await render(
queryAll(".inactive-indicator").index(), hbs`<ThemesList @themes={{this.themes}} @components={{this.components}} @currentTab={{this.currentTab}} />`
-1, );
"there is no inactive themes separator when all themes are inactive"
);
assert.strictEqual(count(".themes-list-item"), 5, "displays all themes");
[2, 3].forEach((num) => this.themes[num].set("user_selectable", true)); assert.strictEqual(
this.themes[4].set("default", true); query(".themes-tab").classList.contains("active"),
this.set("themes", this.themes); true,
const names = [4, 2, 3, 0, 1].map((num) => this.themes[num].get("name")); // default theme always on top, followed by user-selectable ones and then the rest "themes tab is active"
assert.deepEqual( );
Array.from(queryAll(".themes-list-item .name")).map((node) => assert.strictEqual(
node.innerText.trim() query(".components-tab").classList.contains("active"),
), false,
names, "components tab is not active"
"sorts themes correctly" );
);
assert.strictEqual(
queryAll(".inactive-indicator").index(),
3,
"the separator is in the right location"
);
this.themes.forEach((theme) => theme.set("user_selectable", true)); assert.notOk(
this.set("themes", this.themes); exists(".inactive-indicator"),
assert.strictEqual( "there is no inactive themes separator when all themes are inactive"
queryAll(".inactive-indicator").index(), );
-1, assert.strictEqual(count(".themes-list-item"), 5, "displays all themes");
"there is no inactive themes separator when all themes are user-selectable"
);
this.set("themes", []); [2, 3].forEach((num) => this.themes[num].set("user_selectable", true));
assert.strictEqual( this.themes[4].set("default", true);
count(".themes-list-item"), this.set("themes", this.themes);
1, const names = [4, 2, 3, 0, 1].map((num) => this.themes[num].get("name")); // default theme always on top, followed by user-selectable ones and then the rest
"shows one entry with a message when there is nothing to display" assert.deepEqual(
); Array.from(queryAll(".themes-list-item .name")).map((node) =>
assert.strictEqual( node.innerText.trim()
queryAll(".themes-list-item span.empty").text().trim(), ),
I18n.t("admin.customize.theme.empty"), names,
"displays the right message" "sorts themes correctly"
); );
}, assert.strictEqual(
queryAll(".inactive-indicator").index(),
3,
"the separator is in the right location"
);
this.themes.forEach((theme) => theme.set("user_selectable", true));
this.set("themes", this.themes);
assert.notOk(
exists(".inactive-indicator"),
"there is no inactive themes separator when all themes are user-selectable"
);
this.set("themes", []);
assert.strictEqual(
count(".themes-list-item"),
1,
"shows one entry with a message when there is nothing to display"
);
assert.strictEqual(
query(".themes-list-item span.empty").innerText.trim(),
I18n.t("admin.customize.theme.empty"),
"displays the right message"
);
}); });
componentTest("current tab is components", { test("current tab is components", async function (assert) {
template: hbs`{{themes-list themes=themes components=components currentTab=currentTab}}`, this.themes = createThemes(5);
beforeEach() { this.components = createThemes(5, (n) => {
this.themes = createThemes(5); return {
this.components = createThemes(5, (n) => { name: `Child ${n}`,
return { component: true,
name: `Child ${n}`, parentThemes: [this.themes[n - 1]],
component: true, parent_themes: [1, 2, 3, 4, 5],
parentThemes: [this.themes[n - 1]], };
parent_themes: [1, 2, 3, 4, 5], });
}; this.setProperties({
}); themes: this.themes,
this.setProperties({ components: this.components,
themes: this.themes, currentTab: COMPONENTS,
components: this.components, });
currentTab: COMPONENTS,
});
},
test(assert) { await render(
assert.strictEqual( hbs`<ThemesList @themes={{this.themes}} @components={{this.components}} @currentTab={{this.currentTab}} />`
queryAll(".components-tab").hasClass("active"), );
true,
"components tab is active"
);
assert.strictEqual(
queryAll(".themes-tab").hasClass("active"),
false,
"themes tab is not active"
);
assert.strictEqual( assert.strictEqual(
queryAll(".inactive-indicator").index(), query(".components-tab").classList.contains("active"),
-1, true,
"there is no separator" "components tab is active"
); );
assert.strictEqual( assert.strictEqual(
count(".themes-list-item"), query(".themes-tab").classList.contains("active"),
5, false,
"displays all components" "themes tab is not active"
); );
this.set("components", []); assert.notOk(exists(".inactive-indicator"), "there is no separator");
assert.strictEqual( assert.strictEqual(
count(".themes-list-item"), count(".themes-list-item"),
1, 5,
"shows one entry with a message when there is nothing to display" "displays all components"
); );
assert.strictEqual(
queryAll(".themes-list-item span.empty").text().trim(), this.set("components", []);
I18n.t("admin.customize.theme.empty"), assert.strictEqual(
"displays the right message" count(".themes-list-item"),
); 1,
}, "shows one entry with a message when there is nothing to display"
);
assert.strictEqual(
query(".themes-list-item span.empty").innerText.trim(),
I18n.t("admin.customize.theme.empty"),
"displays the right message"
);
}); });
componentTest( test("themes filter is not visible when there are less than 10 themes", async function (assert) {
"themes filter is not visible when there are less than 10 themes", const themes = createThemes(9);
{ this.setProperties({
template: hbs`{{themes-list themes=themes components=[] currentTab=currentTab}}`, themes,
currentTab: THEMES,
});
beforeEach() { await render(
const themes = createThemes(9); hbs`<ThemesList @themes={{this.themes}} components=[] @currentTab={{this.currentTab}} />`
this.setProperties({ );
themes,
currentTab: THEMES,
});
},
async test(assert) {
assert.ok(
!exists(".themes-list-filter"),
"filter input not shown when we have fewer than 10 themes"
);
},
}
);
componentTest( assert.ok(
"themes filter keeps themes whose names include the filter term", !exists(".themes-list-filter"),
{ "filter input not shown when we have fewer than 10 themes"
template: hbs`{{themes-list themes=themes components=[] currentTab=currentTab}}`, );
});
beforeEach() { test("themes filter keeps themes whose names include the filter term", async function (assert) {
const themes = ["osama", "OsAmaa", "osAMA 1234"] const themes = ["osama", "OsAmaa", "osAMA 1234"]
.map((name) => Theme.create({ name: `Theme ${name}` })) .map((name) => Theme.create({ name: `Theme ${name}` }))
.concat(createThemes(7)); .concat(createThemes(7));
this.setProperties({ this.setProperties({
themes, themes,
currentTab: THEMES, currentTab: THEMES,
}); });
},
async test(assert) {
assert.ok(exists(".themes-list-filter"));
await fillIn(".themes-list-filter .filter-input", " oSAma ");
assert.deepEqual(
Array.from(queryAll(".themes-list-item .name")).map((node) =>
node.textContent.trim()
),
["Theme osama", "Theme OsAmaa", "Theme osAMA 1234"],
"only themes whose names include the filter term are shown"
);
},
}
);
componentTest( await render(
"switching between themes and components tabs keeps the filter visible only if both tabs have at least 10 items", hbs`<ThemesList @themes={{this.themes}} components=[] @currentTab={{this.currentTab}} />`
{ );
template: hbs`{{themes-list themes=themes components=components currentTab=currentTab}}`,
beforeEach() { assert.ok(exists(".themes-list-filter"));
const themes = createThemes(10, (n) => { await fillIn(".themes-list-filter .filter-input", " oSAma ");
return { name: `Theme ${n}${n}` }; assert.deepEqual(
}); Array.from(queryAll(".themes-list-item .name")).map((node) =>
const components = createThemes(5, (n) => { node.textContent.trim()
),
["Theme osama", "Theme OsAmaa", "Theme osAMA 1234"],
"only themes whose names include the filter term are shown"
);
});
test("switching between themes and components tabs keeps the filter visible only if both tabs have at least 10 items", async function (assert) {
const themes = createThemes(10, (n) => {
return { name: `Theme ${n}${n}` };
});
const components = createThemes(5, (n) => {
return {
name: `Component ${n}${n}`,
component: true,
parent_themes: [1],
parentThemes: [1],
};
});
this.setProperties({
themes,
components,
currentTab: THEMES,
});
await render(
hbs`<ThemesList @themes={{this.themes}} @components={{this.components}} @currentTab={{this.currentTab}} />`
);
await fillIn(".themes-list-filter .filter-input", "11");
assert.strictEqual(
query(".themes-list-container").textContent.trim(),
"Theme 11",
"only 1 theme is shown"
);
await click(".themes-list-header .components-tab");
assert.ok(
!exists(".themes-list-filter"),
"filter input/term do not persist when we switch to the other" +
" tab because it has fewer than 10 items"
);
assert.deepEqual(
Array.from(queryAll(".themes-list-item .name")).map((node) =>
node.textContent.trim()
),
[
"Component 11",
"Component 22",
"Component 33",
"Component 44",
"Component 55",
],
"all components are shown"
);
this.set(
"components",
this.components.concat(
createThemes(5, (n) => {
n += 5;
return { return {
name: `Component ${n}${n}`, name: `Component ${n}${n}`,
component: true, component: true,
parent_themes: [1], parent_themes: [1],
parentThemes: [1], parentThemes: [1],
}; };
}); })
this.setProperties({ )
themes, );
components, assert.ok(
currentTab: THEMES, exists(".themes-list-filter"),
}); "filter is now shown for the components tab"
}, );
async test(assert) {
await fillIn(".themes-list-filter .filter-input", "11");
assert.strictEqual(
query(".themes-list-container").textContent.trim(),
"Theme 11",
"only 1 theme is shown"
);
await click(".themes-list-header .components-tab");
assert.ok(
!exists(".themes-list-filter"),
"filter input/term do not persist when we switch to the other" +
" tab because it has fewer than 10 items"
);
assert.deepEqual(
Array.from(queryAll(".themes-list-item .name")).map((node) =>
node.textContent.trim()
),
[
"Component 11",
"Component 22",
"Component 33",
"Component 44",
"Component 55",
],
"all components are shown"
);
this.set( await fillIn(".themes-list-filter .filter-input", "66");
"components", assert.strictEqual(
this.components.concat( query(".themes-list-container").textContent.trim(),
createThemes(5, (n) => { "Component 66",
n += 5; "only 1 component is shown"
return { );
name: `Component ${n}${n}`,
component: true,
parent_themes: [1],
parentThemes: [1],
};
})
)
);
assert.ok(
exists(".themes-list-filter"),
"filter is now shown for the components tab"
);
await fillIn(".themes-list-filter .filter-input", "66"); await click(".themes-list-header .themes-tab");
assert.strictEqual( assert.strictEqual(
query(".themes-list-container").textContent.trim(), query(".themes-list-container").textContent.trim(),
"Component 66", "Theme 66",
"only 1 component is shown" "filter term persisted between tabs because both have more than 10 items"
); );
});
await click(".themes-list-header .themes-tab");
assert.strictEqual(
query(".themes-list-container").textContent.trim(),
"Theme 66",
"filter term persisted between tabs because both have more than 10 items"
);
},
}
);
}); });

View File

@ -1,7 +1,6 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -9,51 +8,45 @@ function setTime(time) {
this.setProperties(time); this.setProperties(time);
} }
discourseModule("Integration | Component | time-input", function (hooks) { module("Integration | Component | time-input", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.set("subject", selectKit()); this.set("subject", selectKit());
}); });
componentTest("default", { test("default", async function (assert) {
template: hbs`{{time-input hours=hours minutes=minutes}}`, this.setProperties({ hours: "14", minutes: "58" });
beforeEach() { await render(
this.setProperties({ hours: "14", minutes: "58" }); hbs`<TimeInput @hours={{this.hours}} @minutes={{this.minutes}} />`
}, );
test(assert) { assert.strictEqual(this.subject.header().name(), "14:58");
assert.strictEqual(this.subject.header().name(), "14:58");
},
}); });
componentTest("prevents mutations", { test("prevents mutations", async function (assert) {
template: hbs`{{time-input hours=hours minutes=minutes}}`, this.setProperties({ hours: "14", minutes: "58" });
beforeEach() { await render(
this.setProperties({ hours: "14", minutes: "58" }); hbs`<TimeInput @hours={{this.hours}} @minutes={{this.minutes}} />`
}, );
async test(assert) { await this.subject.expand();
await this.subject.expand(); await this.subject.selectRowByIndex(3);
await this.subject.selectRowByIndex(3); assert.strictEqual(this.subject.header().name(), "14:58");
assert.strictEqual(this.subject.header().name(), "14:58");
},
}); });
componentTest("allows mutations through actions", { test("allows mutations through actions", async function (assert) {
template: hbs`{{time-input hours=hours minutes=minutes onChange=onChange}}`, this.setProperties({ hours: "14", minutes: "58" });
this.set("onChange", setTime);
beforeEach() { await render(
this.setProperties({ hours: "14", minutes: "58" }); hbs`<TimeInput @hours={{this.hours}} @minutes={{this.minutes}} @onChange={{this.onChange}} />`
this.set("onChange", setTime); );
},
async test(assert) { await this.subject.expand();
await this.subject.expand(); await this.subject.selectRowByIndex(3);
await this.subject.selectRowByIndex(3); assert.strictEqual(this.subject.header().name(), "00:45");
assert.strictEqual(this.subject.header().name(), "00:45");
},
}); });
}); });

View File

@ -1,8 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { import {
discourseModule,
exists, exists,
fakeTime, fakeTime,
query, query,
@ -10,222 +9,168 @@ import {
} from "discourse/tests/helpers/qunit-helpers"; } from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n"; import I18n from "I18n";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { click } from "@ember/test-helpers";
discourseModule( module("Integration | Component | time-shortcut-picker", function (hooks) {
"Integration | Component | time-shortcut-picker", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
const template = hbs`{{time-shortcut-picker _itsatrap=itsatrap}}`; hooks.beforeEach(function () {
const itsatrapStub = {
bind: () => {},
unbind: () => {},
};
hooks.beforeEach(function () { this.set("itsatrap", itsatrapStub);
const itsatrapStub = { });
bind: () => {},
unbind: () => {},
};
this.set("itsatrap", itsatrapStub); hooks.afterEach(function () {
}); this.clock?.restore();
});
hooks.afterEach(function () { test("shows default options", async function (assert) {
if (this.clock) { this.siteSettings.suggest_weekends_in_date_pickers = true;
this.clock.restore(); const tuesday = "2100-06-08T08:00:00";
} this.clock = fakeTime(tuesday, this.currentUser.timezone, true);
});
componentTest("shows default options", { await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
template,
beforeEach() { const expected = [
this.siteSettings.suggest_weekends_in_date_pickers = true; I18n.t("time_shortcut.later_today"),
const tuesday = "2100-06-08T08:00:00"; I18n.t("time_shortcut.tomorrow"),
this.clock = fakeTime(tuesday, this.currentUser.timezone, true); I18n.t("time_shortcut.later_this_week"),
}, I18n.t("time_shortcut.this_weekend"),
I18n.t("time_shortcut.start_of_next_business_week"),
I18n.t("time_shortcut.next_month"),
I18n.t("time_shortcut.custom"),
I18n.t("time_shortcut.none"),
];
async test(assert) { const options = Array.from(
const expected = [ queryAll("div.tap-tile-grid div.tap-tile-title").map((_, div) =>
I18n.t("time_shortcut.later_today"), div.innerText.trim()
I18n.t("time_shortcut.tomorrow"), )
I18n.t("time_shortcut.later_this_week"),
I18n.t("time_shortcut.this_weekend"),
I18n.t("time_shortcut.start_of_next_business_week"),
I18n.t("time_shortcut.next_month"),
I18n.t("time_shortcut.custom"),
I18n.t("time_shortcut.none"),
];
const options = Array.from(
queryAll("div.tap-tile-grid div.tap-tile-title").map((_, div) =>
div.innerText.trim()
)
);
assert.deepEqual(options, expected);
},
});
componentTest("show 'Later This Week' if today is < Thursday", {
template,
beforeEach() {
const monday = "2100-06-07T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
},
test(assert) {
assert.ok(
exists("#tap_tile_later_this_week"),
"it has later this week"
);
},
});
componentTest("does not show 'Later This Week' if today is >= Thursday", {
template,
beforeEach() {
const thursday = "2100-06-10T08:00:00";
this.clock = fakeTime(thursday, this.currentUser.timezone, true);
},
test(assert) {
assert.notOk(
exists("#tap_tile_later_this_week"),
"it does not have later this week"
);
},
});
componentTest("does not show 'Later Today' if 'Later Today' is tomorrow", {
template,
beforeEach() {
this.clock = fakeTime(
"2100-12-11T22:00:00", // + 3 hours is tomorrow
this.currentUser.timezone,
true
);
},
test(assert) {
assert.notOk(
exists("#tap_tile_later_today"),
"it does not have later today"
);
},
});
componentTest("shows 'Later Today' if it is before 5pm", {
template,
beforeEach() {
this.clock = fakeTime(
"2100-12-11T16:50:00",
this.currentUser.timezone,
true
);
},
test(assert) {
assert.ok(exists("#tap_tile_later_today"), "it does have later today");
},
});
componentTest("does not show 'Later Today' if it is after 5pm", {
template,
beforeEach() {
this.clock = fakeTime(
"2100-12-11T17:00:00",
this.currentUser.timezone,
true
);
},
test(assert) {
assert.notOk(
exists("#tap_tile_later_today"),
"it does not have later today"
);
},
});
componentTest("defaults to 08:00 for custom time", {
template,
async test(assert) {
await click("#tap_tile_custom");
assert.strictEqual(query("#custom-time").value, "08:00");
},
});
componentTest("shows 'Next Monday' instead of 'Monday' on Sundays", {
template,
beforeEach() {
const sunday = "2100-01-24T08:00:00";
this.clock = fakeTime(sunday, this.currentUser.timezone, true);
},
async test(assert) {
assert.equal(
query("#tap_tile_start_of_next_business_week .tap-tile-title")
.innerText,
"Next Monday"
);
assert.equal(
query("div#tap_tile_start_of_next_business_week div.tap-tile-date")
.innerText,
"Feb 1, 8:00 am"
);
},
});
componentTest("shows 'Next Monday' instead of 'Monday' on Mondays", {
template,
beforeEach() {
const monday = "2100-01-25T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
},
async test(assert) {
assert.equal(
query("#tap_tile_start_of_next_business_week .tap-tile-title")
.innerText,
"Next Monday"
);
assert.equal(
query("div#tap_tile_start_of_next_business_week div.tap-tile-date")
.innerText,
"Feb 1, 8:00 am"
);
},
});
componentTest(
"the 'Next Month' option points to the first day of the next month",
{
template,
beforeEach() {
this.clock = fakeTime(
"2100-01-01T08:00:00",
this.currentUser.timezone,
true
);
},
async test(assert) {
assert.strictEqual(
query("div#tap_tile_next_month div.tap-tile-date").innerText,
"Feb 1, 8:00 am"
);
},
}
); );
}
); assert.deepEqual(options, expected);
});
test("show 'Later This Week' if today is < Thursday", async function (assert) {
const monday = "2100-06-07T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.ok(exists("#tap_tile_later_this_week"), "it has later this week");
});
test("does not show 'Later This Week' if today is >= Thursday", async function (assert) {
const thursday = "2100-06-10T08:00:00";
this.clock = fakeTime(thursday, this.currentUser.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.notOk(
exists("#tap_tile_later_this_week"),
"it does not have later this week"
);
});
test("does not show 'Later Today' if 'Later Today' is tomorrow", async function (assert) {
this.clock = fakeTime(
"2100-12-11T22:00:00", // + 3 hours is tomorrow
this.currentUser.timezone,
true
);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.notOk(
exists("#tap_tile_later_today"),
"it does not have later today"
);
});
test("shows 'Later Today' if it is before 5pm", async function (assert) {
this.clock = fakeTime(
"2100-12-11T16:50:00",
this.currentUser.timezone,
true
);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.ok(exists("#tap_tile_later_today"), "it does have later today");
});
test("does not show 'Later Today' if it is after 5pm", async function (assert) {
this.clock = fakeTime(
"2100-12-11T17:00:00",
this.currentUser.timezone,
true
);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.notOk(
exists("#tap_tile_later_today"),
"it does not have later today"
);
});
test("defaults to 08:00 for custom time", async function (assert) {
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
await click("#tap_tile_custom");
assert.strictEqual(query("#custom-time").value, "08:00");
});
test("shows 'Next Monday' instead of 'Monday' on Sundays", async function (assert) {
const sunday = "2100-01-24T08:00:00";
this.clock = fakeTime(sunday, this.currentUser.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.strictEqual(
query("#tap_tile_start_of_next_business_week .tap-tile-title").innerText,
"Next Monday"
);
assert.strictEqual(
query("div#tap_tile_start_of_next_business_week div.tap-tile-date")
.innerText,
"Feb 1, 8:00 am"
);
});
test("shows 'Next Monday' instead of 'Monday' on Mondays", async function (assert) {
const monday = "2100-01-25T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.strictEqual(
query("#tap_tile_start_of_next_business_week .tap-tile-title").innerText,
"Next Monday"
);
assert.strictEqual(
query("div#tap_tile_start_of_next_business_week div.tap-tile-date")
.innerText,
"Feb 1, 8:00 am"
);
});
test("the 'Next Month' option points to the first day of the next month", async function (assert) {
this.clock = fakeTime(
"2100-01-01T08:00:00",
this.currentUser.timezone,
true
);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
assert.strictEqual(
query("div#tap_tile_next_month div.tap-tile-date").innerText,
"Feb 1, 8:00 am"
);
});
});

View File

@ -1,42 +1,37 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { queryAll } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | topic-list-item", function (hooks) { module("Integration | Component | topic-list-item", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("checkbox is rendered checked if topic is in selected array", { test("checkbox is rendered checked if topic is in selected array", async function (assert) {
template: hbs`{{topic-list-item const topic = Topic.create({ id: 24234 });
topic=topic const topic2 = Topic.create({ id: 24235 });
bulkSelectEnabled=true this.setProperties({
selected=selected topic,
}} topic2,
{{topic-list-item selected: [topic],
topic=topic2 });
bulkSelectEnabled=true
selected=selected
}}`,
beforeEach() { await render(hbs`
const topic = Topic.create({ id: 24234 }); <TopicListItem
const topic2 = Topic.create({ id: 24235 }); @topic={{this.topic}}
this.setProperties({ @bulkSelectEnabled={{true}}
topic, @selected={{this.selected}}
topic2, />
selected: [topic], <TopicListItem
}); @topic={{this.topic2}}
}, @bulkSelectEnabled={{true}}
@selected={{this.selected}}
/>
`);
async test(assert) { const checkboxes = queryAll("input.bulk-select");
const checkboxes = queryAll("input.bulk-select"); assert.ok(checkboxes[0].checked);
assert.ok(checkboxes[0].checked); assert.ok(!checkboxes[1].checked);
assert.ok(!checkboxes[1].checked);
},
}); });
}); });

View File

@ -1,70 +1,64 @@
import { click } from "@ember/test-helpers"; import { module, test } from "qunit";
import componentTest, { import { setupRenderingTest } from "discourse/tests/helpers/component-test";
setupRenderingTest, import { click, render } from "@ember/test-helpers";
} from "discourse/tests/helpers/component-test";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | topic-list", function (hooks) { module("Integration | Component | topic-list", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("bulk select", { test("bulk select", async function (assert) {
template: hbs`{{topic-list this.setProperties({
canBulkSelect=true topics: [Topic.create({ id: 24234 }), Topic.create({ id: 24235 })],
toggleBulkSelect=toggleBulkSelect selected: [],
bulkSelectEnabled=bulkSelectEnabled bulkSelectEnabled: false,
autoAddTopicsToBulkSelect=autoAddTopicsToBulkSelect autoAddTopicsToBulkSelect: false,
updateAutoAddTopicsToBulkSelect=updateAutoAddTopicsToBulkSelect
topics=topics
selected=selected
}}`,
beforeEach() { toggleBulkSelect() {
const topic = Topic.create({ id: 24234 }); this.toggleProperty("bulkSelectEnabled");
const topic2 = Topic.create({ id: 24235 }); },
this.setProperties({
topics: [topic, topic2],
selected: [],
bulkSelectEnabled: false,
autoAddTopicsToBulkSelect: false,
toggleBulkSelect() { updateAutoAddTopicsToBulkSelect(newVal) {
this.toggleProperty("bulkSelectEnabled"); this.set("autoAddTopicsToBulkSelect", newVal);
}, },
});
updateAutoAddTopicsToBulkSelect(newVal) { await render(hbs`
this.set("autoAddTopicsToBulkSelect", newVal); <TopicList
}, @canBulkSelect={{true}}
}); @toggleBulkSelect={{this.toggleBulkSelect}}
}, @bulkSelectEnabled={{this.bulkSelectEnabled}}
@autoAddTopicsToBulkSelect={{this.autoAddTopicsToBulkSelect}}
@updateAutoAddTopicsToBulkSelect={{this.updateAutoAddTopicsToBulkSelect}}
@topics={{this.topics}}
@selected={{this.selected}}
/>
`);
async test(assert) { assert.strictEqual(this.selected.length, 0, "defaults to 0");
assert.strictEqual(this.selected.length, 0, "defaults to 0"); await click("button.bulk-select");
await click("button.bulk-select"); assert.ok(this.bulkSelectEnabled, "bulk select is enabled");
assert.ok(this.bulkSelectEnabled, "bulk select is enabled");
await click("button.bulk-select-all"); await click("button.bulk-select-all");
assert.strictEqual( assert.strictEqual(
this.selected.length, this.selected.length,
2, 2,
"clicking Select All selects all loaded topics" "clicking Select All selects all loaded topics"
); );
assert.ok( assert.ok(
this.autoAddTopicsToBulkSelect, this.autoAddTopicsToBulkSelect,
"clicking Select All turns on the autoAddTopicsToBulkSelect flag" "clicking Select All turns on the autoAddTopicsToBulkSelect flag"
); );
await click("button.bulk-clear-all"); await click("button.bulk-clear-all");
assert.strictEqual( assert.strictEqual(
this.selected.length, this.selected.length,
0, 0,
"clicking Clear All deselects all topics" "clicking Clear All deselects all topics"
); );
assert.ok( assert.ok(
!this.autoAddTopicsToBulkSelect, !this.autoAddTopicsToBulkSelect,
"clicking Clear All turns off the autoAddTopicsToBulkSelect flag" "clicking Clear All turns off the autoAddTopicsToBulkSelect flag"
); );
},
}); });
}); });

View File

@ -1,100 +1,88 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render } from "@ember/test-helpers";
import { import { count, exists } from "discourse/tests/helpers/qunit-helpers";
count,
discourseModule,
exists,
} from "discourse/tests/helpers/qunit-helpers";
import { click } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module("Integration | Component | uppy-image-uploader", function (hooks) {
"Integration | Component | uppy-image-uploader", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("with image", { test("with image", async function (assert) {
template: hbs` await render(hbs`
{{uppy-image-uploader id="test-uppy-image-uploader" imageUrl='/images/avatar.png' placeholderUrl='/not/used.png'}} <UppyImageUploader @id="test-uppy-image-uploader" @imageUrl="/images/avatar.png" @placeholderUrl="/not/used.png" />
`, `);
async test(assert) { assert.strictEqual(
assert.strictEqual( count(".d-icon-far-image"),
count(".d-icon-far-image"), 1,
1, "it displays the upload icon"
"it displays the upload icon" );
);
assert.strictEqual( assert.strictEqual(
count(".d-icon-far-trash-alt"), count(".d-icon-far-trash-alt"),
1, 1,
"it displays the trash icon" "it displays the trash icon"
); );
assert.ok( assert.ok(
!exists(".placeholder-overlay"), !exists(".placeholder-overlay"),
"it does not display the placeholder image" "it does not display the placeholder image"
); );
await click(".image-uploader-lightbox-btn"); await click(".image-uploader-lightbox-btn");
assert.strictEqual( assert.strictEqual(
document.querySelectorAll(".mfp-container").length, document.querySelectorAll(".mfp-container").length,
1, 1,
"it displays the image lightbox" "it displays the image lightbox"
); );
}, });
});
componentTest("without image", { test("without image", async function (assert) {
template: hbs`{{uppy-image-uploader id="test-uppy-image-uploader"}}`, await render(hbs`<UppyImageUploader @id="test-uppy-image-uploader" />`);
test(assert) { assert.strictEqual(
assert.strictEqual( count(".d-icon-far-image"),
count(".d-icon-far-image"), 1,
1, "it displays the upload icon"
"it displays the upload icon" );
);
assert.ok( assert.ok(
!exists(".d-icon-far-trash-alt"), !exists(".d-icon-far-trash-alt"),
"it does not display trash icon" "it does not display trash icon"
); );
assert.ok( assert.ok(
!exists(".image-uploader-lightbox-btn"), !exists(".image-uploader-lightbox-btn"),
"it does not display the button to open image lightbox" "it does not display the button to open image lightbox"
); );
}, });
});
componentTest("with placeholder", { test("with placeholder", async function (assert) {
template: hbs`{{uppy-image-uploader id="test-uppy-image-uploader" placeholderUrl='/images/avatar.png'}}`, await render(
hbs`<UppyImageUploader @id="test-uppy-image-uploader" @placeholderUrl="/images/avatar.png" />`
);
test(assert) { assert.strictEqual(
assert.strictEqual( count(".d-icon-far-image"),
count(".d-icon-far-image"), 1,
1, "it displays the upload icon"
"it displays the upload icon" );
);
assert.ok( assert.ok(
!exists(".d-icon-far-trash-alt"), !exists(".d-icon-far-trash-alt"),
"it does not display trash icon" "it does not display trash icon"
); );
assert.ok( assert.ok(
!exists(".image-uploader-lightbox-btn"), !exists(".image-uploader-lightbox-btn"),
"it does not display the button to open image lightbox" "it does not display the button to open image lightbox"
); );
assert.strictEqual( assert.strictEqual(
count(".placeholder-overlay"), count(".placeholder-overlay"),
1, 1,
"it displays the placeholder image" "it displays the placeholder image"
); );
}, });
}); });
}
);

View File

@ -1,11 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { resetFlair } from "discourse/lib/avatar-flair"; import { resetFlair } from "discourse/lib/avatar-flair";
@ -42,177 +38,140 @@ function setupSiteGroups(that) {
]; ];
} }
discourseModule( module("Integration | Component | user-avatar-flair", function (hooks) {
"Integration | Component | user-avatar-flair", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("avatar flair for admin user", { hooks.beforeEach(function () {
template: hbs`{{user-avatar-flair user=args}}`, resetFlair();
beforeEach() { });
resetFlair();
this.set("args", { hooks.afterEach(function () {
admin: true, resetFlair();
moderator: false, });
trust_level: 2,
}); test("avatar flair for admin user", async function (assert) {
setupSiteGroups(this); this.set("args", {
}, admin: true,
afterEach() { moderator: false,
resetFlair(); trust_level: 2,
}, });
test(assert) { setupSiteGroups(this);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-bars"), "it has the svg icon"); await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
assert.strictEqual(
queryAll(".avatar-flair").attr("style"), assert.ok(exists(".avatar-flair"), "it has the tag");
"background-color: #CC000A; color: #FFFFFA; ", assert.ok(exists("svg.d-icon-bars"), "it has the svg icon");
"it has styles" assert.strictEqual(
); query(".avatar-flair").getAttribute("style"),
}, "background-color: #CC000A; color: #FFFFFA; ",
"it has styles"
);
});
test("avatar flair for moderator user with fallback to staff", async function (assert) {
this.set("args", {
admin: false,
moderator: true,
trust_level: 2,
});
setupSiteGroups(this);
await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-bars"), "it has the svg icon");
assert.strictEqual(
query(".avatar-flair").getAttribute("style"),
"background-color: #CC0005; color: #FFFFF5; ",
"it has styles"
);
});
test("avatar flair for trust level", async function (assert) {
this.set("args", {
admin: false,
moderator: false,
trust_level: 2,
});
setupSiteGroups(this);
await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-dice-two"), "it has the svg icon");
assert.strictEqual(
query(".avatar-flair").getAttribute("style"),
"background-color: #CC0002; color: #FFFFF2; ",
"it has styles"
);
});
test("avatar flair for trust level with fallback", async function (assert) {
this.set("args", {
admin: false,
moderator: false,
trust_level: 3,
});
setupSiteGroups(this);
await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-dice-two"), "it has the svg icon");
assert.strictEqual(
query(".avatar-flair").getAttribute("style"),
"background-color: #CC0002; color: #FFFFF2; ",
"it has styles"
);
});
test("avatar flair for login-required site, before login", async function (assert) {
this.set("args", {
admin: false,
moderator: false,
trust_level: 3,
});
// Groups not serialized for anon on login_required
this.site.groups = undefined;
await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
assert.ok(!exists(".avatar-flair"), "it does not render a flair");
});
test("avatar flair for primary group flair", async function (assert) {
this.set("args", {
admin: false,
moderator: false,
trust_level: 3,
flair_name: "Band Geeks",
flair_url: "fa-times",
flair_bg_color: "123456",
flair_color: "B0B0B0",
primary_group_name: "Band Geeks",
});
setupSiteGroups(this);
await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-times"), "it has the svg icon");
assert.strictEqual(
query(".avatar-flair").getAttribute("style"),
"background-color: #123456; color: #B0B0B0; ",
"it has styles"
);
});
test("user-avatar-flair for user with no flairs", async function (assert) {
this.set("args", {
admin: false,
moderator: false,
trust_level: 1,
}); });
componentTest("avatar flair for moderator user with fallback to staff", { await render(hbs`<UserAvatarFlair @user={{this.args}} />`);
template: hbs`{{user-avatar-flair user=args}}`,
beforeEach() {
resetFlair();
this.set("args", {
admin: false,
moderator: true,
trust_level: 2,
});
setupSiteGroups(this);
},
afterEach() {
resetFlair();
},
test(assert) {
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-bars"), "it has the svg icon");
assert.strictEqual(
queryAll(".avatar-flair").attr("style"),
"background-color: #CC0005; color: #FFFFF5; ",
"it has styles"
);
},
});
componentTest("avatar flair for trust level", { assert.ok(!exists(".avatar-flair"), "it does not render a flair");
template: hbs`{{user-avatar-flair user=args}}`, });
beforeEach() { });
resetFlair();
this.set("args", {
admin: false,
moderator: false,
trust_level: 2,
});
setupSiteGroups(this);
},
afterEach() {
resetFlair();
},
test(assert) {
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-dice-two"), "it has the svg icon");
assert.strictEqual(
queryAll(".avatar-flair").attr("style"),
"background-color: #CC0002; color: #FFFFF2; ",
"it has styles"
);
},
});
componentTest("avatar flair for trust level with fallback", {
template: hbs`{{user-avatar-flair user=args}}`,
beforeEach() {
resetFlair();
this.set("args", {
admin: false,
moderator: false,
trust_level: 3,
});
setupSiteGroups(this);
},
afterEach() {
resetFlair();
},
test(assert) {
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-dice-two"), "it has the svg icon");
assert.strictEqual(
queryAll(".avatar-flair").attr("style"),
"background-color: #CC0002; color: #FFFFF2; ",
"it has styles"
);
},
});
componentTest("avatar flair for login-required site, before login", {
template: hbs`{{user-avatar-flair user=args}}`,
beforeEach() {
resetFlair();
this.set("args", {
admin: false,
moderator: false,
trust_level: 3,
});
// Groups not serialized for anon on login_required
this.site.groups = undefined;
},
afterEach() {
resetFlair();
},
test(assert) {
assert.ok(!exists(".avatar-flair"), "it does not render a flair");
},
});
componentTest("avatar flair for primary group flair", {
template: hbs`{{user-avatar-flair user=args}}`,
beforeEach() {
resetFlair();
this.set("args", {
admin: false,
moderator: false,
trust_level: 3,
flair_name: "Band Geeks",
flair_url: "fa-times",
flair_bg_color: "123456",
flair_color: "B0B0B0",
primary_group_name: "Band Geeks",
});
setupSiteGroups(this);
},
afterEach() {
resetFlair();
},
test(assert) {
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-times"), "it has the svg icon");
assert.strictEqual(
queryAll(".avatar-flair").attr("style"),
"background-color: #123456; color: #B0B0B0; ",
"it has styles"
);
},
});
componentTest("user-avatar-flair for user with no flairs", {
template: hbs`{{user-avatar-flair user=args}}`,
beforeEach() {
resetFlair();
this.set("args", {
admin: false,
moderator: false,
trust_level: 1,
});
},
afterEach() {
resetFlair();
},
test(assert) {
assert.ok(!exists(".avatar-flair"), "it does not render a flair");
},
});
}
);

View File

@ -1,71 +1,53 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { import { exists, query } from "discourse/tests/helpers/qunit-helpers";
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
discourseModule("Integration | Component | user-info", function (hooks) { module("Integration | Component | user-info", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("prioritized name", { test("prioritized name", async function (assert) {
template: hbs`{{user-info user=currentUser}}`, this.siteSettings.prioritize_username_in_ux = false;
this.currentUser.name = "Evil Trout";
beforeEach() { await render(hbs`<UserInfo @user={{this.currentUser}} />`);
this.siteSettings.prioritize_username_in_ux = false;
this.currentUser.name = "Evil Trout";
},
async test(assert) { assert.strictEqual(query(".name.bold").innerText.trim(), "Evil Trout");
assert.equal(query(".name.bold").innerText.trim(), "Evil Trout"); assert.strictEqual(query(".username.margin").innerText.trim(), "eviltrout");
assert.equal(query(".username.margin").innerText.trim(), "eviltrout");
},
}); });
componentTest("prioritized username", { test("prioritized username", async function (assert) {
template: hbs`{{user-info user=currentUser}}`, this.siteSettings.prioritize_username_in_ux = true;
this.currentUser.name = "Evil Trout";
beforeEach() { await render(hbs`<UserInfo @user={{this.currentUser}} />`);
this.siteSettings.prioritize_username_in_ux = true;
this.currentUser.name = "Evil Trout";
},
async test(assert) { assert.strictEqual(query(".username.bold").innerText.trim(), "eviltrout");
assert.equal(query(".username.bold").innerText.trim(), "eviltrout"); assert.strictEqual(query(".name.margin").innerText.trim(), "Evil Trout");
assert.equal(query(".name.margin").innerText.trim(), "Evil Trout");
},
}); });
componentTest("includeLink", { test("includeLink", async function (assert) {
template: hbs`{{user-info user=currentUser includeLink=includeLink}}`, await render(
hbs`<UserInfo @user={{this.currentUser}} @includeLink={{this.includeLink}} />`
);
async test(assert) { this.set("includeLink", true);
this.set("includeLink", true); assert.ok(exists(`.username a[href="/u/${this.currentUser.username}"]`));
assert.ok(exists(`.username a[href="/u/${this.currentUser.username}"]`)); this.set("includeLink", false);
assert.notOk(exists(`.username a[href="/u/${this.currentUser.username}"]`));
this.set("includeLink", false);
assert.notOk(
exists(`.username a[href="/u/${this.currentUser.username}"]`)
);
},
}); });
componentTest("includeAvatar", { test("includeAvatar", async function (assert) {
template: hbs`{{user-info user=currentUser includeAvatar=includeAvatar}}`, await render(
hbs`<UserInfo @user={{this.currentUser}} @includeAvatar={{this.includeAvatar}} />`
);
async test(assert) { this.set("includeAvatar", true);
this.set("includeAvatar", true); assert.ok(exists(".user-image"));
assert.ok(exists(".user-image")); this.set("includeAvatar", false);
assert.notOk(exists(".user-image"));
this.set("includeAvatar", false);
assert.notOk(exists(".user-image"));
},
}); });
}); });

View File

@ -1,7 +1,7 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { render } from "@ember/test-helpers";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
function paste(element, text) { function paste(element, text) {
@ -10,51 +10,47 @@ function paste(element, text) {
element.dispatchEvent(e); element.dispatchEvent(e);
} }
discourseModule("Integration | Component | user-selector", function (hooks) { module("Integration | Component | user-selector", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("pasting a list of usernames", { test("pasting a list of usernames", async function (assert) {
template: hbs`{{user-selector usernames=usernames class="test-selector"}}`, this.set("usernames", "evil,trout");
beforeEach() { await render(
this.set("usernames", "evil,trout"); hbs`<UserSelector @usernames={{this.usernames}} class="test-selector" />`
}, );
test(assert) { let element = query(".test-selector");
let element = query(".test-selector");
assert.strictEqual(this.get("usernames"), "evil,trout"); assert.strictEqual(this.get("usernames"), "evil,trout");
paste(element, "zip,zap,zoom"); paste(element, "zip,zap,zoom");
assert.strictEqual(this.get("usernames"), "evil,trout,zip,zap,zoom"); assert.strictEqual(this.get("usernames"), "evil,trout,zip,zap,zoom");
paste(element, "evil,abc,abc,abc"); paste(element, "evil,abc,abc,abc");
assert.strictEqual(this.get("usernames"), "evil,trout,zip,zap,zoom,abc"); assert.strictEqual(this.get("usernames"), "evil,trout,zip,zap,zoom,abc");
this.set("usernames", ""); this.set("usernames", "");
paste(element, "names with spaces"); paste(element, "names with spaces");
assert.strictEqual(this.get("usernames"), "names,with,spaces"); assert.strictEqual(this.get("usernames"), "names,with,spaces");
this.set("usernames", null); this.set("usernames", null);
paste(element, "@eviltrout,@codinghorror sam"); paste(element, "@eviltrout,@codinghorror sam");
assert.strictEqual(this.get("usernames"), "eviltrout,codinghorror,sam"); assert.strictEqual(this.get("usernames"), "eviltrout,codinghorror,sam");
this.set("usernames", null); this.set("usernames", null);
paste(element, "eviltrout\nsam\ncodinghorror"); paste(element, "eviltrout\nsam\ncodinghorror");
assert.strictEqual(this.get("usernames"), "eviltrout,sam,codinghorror"); assert.strictEqual(this.get("usernames"), "eviltrout,sam,codinghorror");
},
}); });
componentTest("excluding usernames", { test("excluding usernames", async function (assert) {
template: hbs`{{user-selector usernames=usernames excludedUsernames=excludedUsernames class="test-selector"}}`, this.set("usernames", "mark");
this.set("excludedUsernames", ["jeff", "sam", "robin"]);
beforeEach() { await render(
this.set("usernames", "mark"); hbs`<UserSelector @usernames={{this.usernames}} @excludedUsernames={{this.excludedUsernames}} class="test-selector" />`
this.set("excludedUsernames", ["jeff", "sam", "robin"]); );
},
test(assert) { let element = query(".test-selector");
let element = query(".test-selector"); paste(element, "roman,penar,jeff,robin");
paste(element, "roman,penar,jeff,robin"); assert.strictEqual(this.get("usernames"), "mark,roman,penar");
assert.strictEqual(this.get("usernames"), "mark,roman,penar");
},
}); });
}); });

View File

@ -1,170 +1,145 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { blur, click, fillIn, render } from "@ember/test-helpers";
import { import { count, query } from "discourse/tests/helpers/qunit-helpers";
count,
discourseModule,
query,
} from "discourse/tests/helpers/qunit-helpers";
import { blur, click, fillIn } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
discourseModule("Integration | Component | value-list", function (hooks) { module("Integration | Component | value-list", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
componentTest("adding a value", { test("adding a value", async function (assert) {
template: hbs`{{value-list values=values}}`, this.set("values", "vinkas\nosama");
beforeEach() { await render(hbs`<ValueList @values={{this.values}} />`);
this.set("values", "vinkas\nosama");
},
async test(assert) { await selectKit().expand();
await selectKit().expand(); await selectKit().fillInFilter("eviltrout");
await selectKit().fillInFilter("eviltrout"); await selectKit().keyboard("Enter");
await selectKit().keyboard("Enter");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.deepEqual( assert.strictEqual(
this.values, this.values,
"vinkas\nosama\neviltrout", "vinkas\nosama\neviltrout",
"it adds the value to the list of values" "it adds the value to the list of values"
); );
},
}); });
componentTest("changing a value", { test("changing a value", async function (assert) {
template: hbs`{{value-list values=values}}`, this.set("values", "vinkas\nosama");
beforeEach() { await render(hbs`<ValueList @values={{this.values}} />`);
this.set("values", "vinkas\nosama");
},
async test(assert) { await fillIn(".values .value[data-index='1'] .value-input", "jarek");
await fillIn(".values .value[data-index='1'] .value-input", "jarek"); await blur(".values .value[data-index='1'] .value-input");
await blur(".values .value[data-index='1'] .value-input");
assert.strictEqual( assert.strictEqual(
query(".values .value[data-index='1'] .value-input").value, query(".values .value[data-index='1'] .value-input").value,
"jarek" "jarek"
); );
assert.deepEqual(this.values, "vinkas\njarek", "updates the value list"); assert.deepEqual(this.values, "vinkas\njarek", "updates the value list");
},
}); });
componentTest("removing a value", { test("removing a value", async function (assert) {
template: hbs`{{value-list values=values}}`, this.set("values", "vinkas\nosama");
beforeEach() { await render(hbs`<ValueList @values={{this.values}} />`);
this.set("values", "vinkas\nosama");
},
async test(assert) { await click(".values .value[data-index='0'] .remove-value-btn");
await click(".values .value[data-index='0'] .remove-value-btn");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
1, 1,
"it removes the value from the list of values" "it removes the value from the list of values"
); );
assert.strictEqual(this.values, "osama", "it removes the expected value"); assert.strictEqual(this.values, "osama", "it removes the expected value");
await selectKit().expand(); await selectKit().expand();
assert.ok( assert.strictEqual(
query(".select-kit-collection li.select-kit-row span.name") query(".select-kit-collection li.select-kit-row span.name").innerText,
.innerText === "vinkas", "vinkas",
"it adds the removed value to choices" "it adds the removed value to choices"
); );
},
}); });
componentTest("selecting a value", { test("selecting a value", async function (assert) {
template: hbs`{{value-list values=values choices=choices}}`, this.setProperties({
values: "vinkas\nosama",
choices: ["maja", "michael"],
});
beforeEach() { await render(
this.setProperties({ hbs`<ValueList @values={{this.values}} @choices={{this.choices}} />`
values: "vinkas\nosama", );
choices: ["maja", "michael"],
});
},
async test(assert) { await selectKit().expand();
await selectKit().expand(); await selectKit().selectRowByValue("maja");
await selectKit().selectRowByValue("maja");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.deepEqual( assert.strictEqual(
this.values, this.values,
"vinkas\nosama\nmaja", "vinkas\nosama\nmaja",
"it adds the value to the list of values" "it adds the value to the list of values"
); );
},
}); });
componentTest("array support", { test("array support", async function (assert) {
template: hbs`{{value-list values=values inputType='array'}}`, this.set("values", ["vinkas", "osama"]);
beforeEach() { await render(hbs`<ValueList @values={{this.values}} @inputType="array" />`);
this.set("values", ["vinkas", "osama"]);
},
async test(assert) { this.set("values", ["vinkas", "osama"]);
this.set("values", ["vinkas", "osama"]);
await selectKit().expand(); await selectKit().expand();
await selectKit().fillInFilter("eviltrout"); await selectKit().fillInFilter("eviltrout");
await selectKit().selectRowByValue("eviltrout"); await selectKit().selectRowByValue("eviltrout");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.deepEqual( assert.deepEqual(
this.values, this.values,
["vinkas", "osama", "eviltrout"], ["vinkas", "osama", "eviltrout"],
"it adds the value to the list of values" "it adds the value to the list of values"
); );
},
}); });
componentTest("delimiter support", { test("delimiter support", async function (assert) {
template: hbs`{{value-list values=values inputDelimiter='|'}}`, this.set("values", "vinkas|osama");
beforeEach() { await render(
this.set("values", "vinkas|osama"); hbs`<ValueList @values={{this.values}} @inputDelimiter="|" />`
}, );
async test(assert) { await selectKit().expand();
await selectKit().expand(); await selectKit().fillInFilter("eviltrout");
await selectKit().fillInFilter("eviltrout"); await selectKit().keyboard("Enter");
await selectKit().keyboard("Enter");
assert.strictEqual( assert.strictEqual(
count(".values .value"), count(".values .value"),
3, 3,
"it adds the value to the list of values" "it adds the value to the list of values"
); );
assert.deepEqual( assert.strictEqual(
this.values, this.values,
"vinkas|osama|eviltrout", "vinkas|osama|eviltrout",
"it adds the value to the list of values" "it adds the value to the list of values"
); );
},
}); });
}); });

View File

@ -1,51 +1,45 @@
import componentTest, { import { module, test } from "qunit";
setupRenderingTest, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
} from "discourse/tests/helpers/component-test"; import { click, render, waitFor } from "@ember/test-helpers";
import { import { createFile } from "discourse/tests/helpers/qunit-helpers";
createFile,
discourseModule,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import pretender, { response } from "discourse/tests/helpers/create-pretender"; import pretender, { response } from "discourse/tests/helpers/create-pretender";
import { click, waitFor } from "@ember/test-helpers";
discourseModule( module("Integration | Component | watched-word-uploader", function (hooks) {
"Integration | Component | watched-word-uploader", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
pretender.post("/admin/customize/watched_words/upload.json", function () { pretender.post("/admin/customize/watched_words/upload.json", function () {
return response(200, {}); return response(200, {});
}); });
});
test("sets the proper action key on uploads", async function (assert) {
const done = assert.async();
this.set("actionNameKey", "flag");
this.set("doneUpload", function () {
assert.strictEqual(
Object.entries(this._uppyInstance.getState().files)[0][1].meta
.action_key,
"flag"
);
done();
}); });
componentTest("sets the proper action key on uploads", { await render(hbs`
template: hbs`{{watched-word-uploader <WatchedWordUploader
id="watched-word-uploader" @id="watched-word-uploader"
actionKey=actionNameKey @actionKey={{this.actionNameKey}}
done=doneUpload @done={{this.doneUpload}}
}}`, />
`);
async test(assert) { const words = createFile("watched-words.txt");
const done = assert.async(); await this.container
this.set("actionNameKey", "flag"); .lookup("service:app-events")
this.set("doneUpload", function () { .trigger("upload-mixin:watched-word-uploader:add-files", words);
assert.equal( await waitFor(".bootbox span.d-button-label");
Object.entries(this._uppyInstance.getState().files)[0][1].meta
.action_key,
"flag"
);
done();
});
const words = createFile("watched-words.txt"); await click(".bootbox span.d-button-label");
await this.container });
.lookup("service:app-events") });
.trigger("upload-mixin:watched-word-uploader:add-files", words);
await waitFor(".bootbox span.d-button-label");
await click(".bootbox span.d-button-label");
},
});
}
);

View File

@ -0,0 +1,32 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | actions-summary", function (hooks) {
setupRenderingTest(hooks);
test("post deleted", async function (assert) {
this.set("args", {
deleted_at: "2016-01-01",
deletedByUsername: "eviltrout",
deletedByAvatarTemplate: "/images/avatar.png",
});
await render(
hbs`<MountWidget @widget="actions-summary" @args={{this.args}} />`
);
assert.strictEqual(
count(".post-action .d-icon-far-trash-alt"),
1,
"it has the deleted icon"
);
assert.strictEqual(
count(".avatar[title=eviltrout]"),
1,
"it has the deleted by avatar"
);
});
});

View File

@ -0,0 +1,42 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | avatar-flair", function (hooks) {
setupRenderingTest(hooks);
test("avatar flair with an icon", async function (assert) {
this.set("args", {
flair_url: "fa-bars",
flair_bg_color: "CC0000",
flair_color: "FFFFFF",
});
await render(
hbs`<MountWidget @widget="avatar-flair" @args={{this.args}} />`
);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-bars"), "it has the svg icon");
assert.strictEqual(
query(".avatar-flair").getAttribute("style"),
"background-color: #CC0000; color: #FFFFFF; ",
"it has styles"
);
});
test("avatar flair with an image", async function (assert) {
this.set("args", {
flair_url: "/images/avatar.png",
});
await render(
hbs`<MountWidget @widget="avatar-flair" @args={{this.args}} />`
);
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(!exists("svg"), "it does not have an svg icon");
});
});

View File

@ -0,0 +1,66 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | button", function (hooks) {
setupRenderingTest(hooks);
test("icon only button", async function (assert) {
this.set("args", { icon: "far-smile" });
await render(hbs`<MountWidget @widget="button" @args={{this.args}} />`);
assert.ok(exists("button.btn.btn-icon.no-text"), "it has all the classes");
assert.ok(exists("button .d-icon.d-icon-far-smile"), "it has the icon");
});
test("icon and text button", async function (assert) {
this.set("args", { icon: "plus", label: "topic.create" });
await render(hbs`<MountWidget @widget="button" @args={{this.args}} />`);
assert.ok(exists("button.btn.btn-icon-text"), "it has all the classes");
assert.ok(exists("button .d-icon.d-icon-plus"), "it has the icon");
assert.ok(exists("button span.d-button-label"), "it has the label");
});
test("emoji and text button", async function (assert) {
this.set("args", { emoji: "mega", label: "topic.create" });
await render(hbs`<MountWidget @widget="button" @args={{this.args}} />`);
assert.ok(exists("button.widget-button"), "renders the widget");
assert.ok(exists("button img.emoji"), "it renders the emoji");
assert.ok(exists("button span.d-button-label"), "it renders the label");
});
test("text only button", async function (assert) {
this.set("args", { label: "topic.create" });
await render(hbs`<MountWidget @widget="button" @args={{this.args}} />`);
assert.ok(exists("button.btn.btn-text"), "it has all the classes");
assert.ok(exists("button span.d-button-label"), "it has the label");
});
test("translatedLabel", async function (assert) {
this.set("args", { translatedLabel: "foo bar" });
await render(hbs`<MountWidget @widget="button" @args={{this.args}} />`);
assert.strictEqual(
query("button span.d-button-label").innerText,
"foo bar"
);
});
test("translatedTitle", async function (assert) {
this.set("args", { label: "topic.create", translatedTitle: "foo bar" });
await render(hbs`<MountWidget @widget="button" @args={{this.args}} />`);
assert.strictEqual(query("button").title, "foo bar");
});
});

View File

@ -0,0 +1,62 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render, triggerEvent } from "@ember/test-helpers";
import { count, exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import EmberObject from "@ember/object";
module(
"Integration | Component | Widget | default-notification-item",
function (hooks) {
setupRenderingTest(hooks);
test("sets notification as read on middle click", async function (assert) {
this.set(
"args",
EmberObject.create({
id: 3,
user_id: 1,
notification_type: 6,
read: false,
created_at: "2020-01-01T12:00:00.000Z",
post_number: 1,
topic_id: 10,
fancy_title: "Greetings!",
slug: "greetings",
data: {
topic_title: "Greetings!",
original_post_id: 14,
original_post_type: 1,
original_username: "discobot",
revision_number: null,
display_username: "discobot",
},
})
);
await render(
hbs`<MountWidget @widget="default-notification-item" @args={{this.args}} />`
);
let requests = 0;
pretender.put("/notifications/mark-read", (request) => {
++requests;
assert.strictEqual(
request.requestBody,
`id=${this.args.id}`,
"it sets correct request parameters"
);
return response({ success: true });
});
assert.ok(!exists("li.read"));
await triggerEvent("li", "mouseup", { button: 1, which: 2 });
assert.strictEqual(count("li.read"), 1);
assert.strictEqual(requests, 1);
});
}
);

View File

@ -0,0 +1,213 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count, exists, queryAll } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import { NotificationLevels } from "discourse/lib/notification-levels";
const topCategoryIds = [2, 3, 1];
let mutedCategoryIds = [];
let unreadCategoryIds = [];
let categoriesByCount = [];
module("Integration | Component | Widget | hamburger-menu", function (hooks) {
setupRenderingTest(hooks);
test("prioritize faq", async function (assert) {
this.siteSettings.faq_url = "http://example.com/faq";
this.currentUser.set("read_faq", false);
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(exists(".faq-priority"));
assert.ok(!exists(".faq-link"));
});
test("prioritize faq - user has read", async function (assert) {
this.siteSettings.faq_url = "http://example.com/faq";
this.currentUser.set("read_faq", true);
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(!exists(".faq-priority"));
assert.ok(exists(".faq-link"));
});
test("staff menu - not staff", async function (assert) {
this.currentUser.set("staff", false);
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(!exists(".admin-link"));
});
test("staff menu - moderator", async function (assert) {
this.currentUser.set("moderator", true);
this.currentUser.set("can_review", true);
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(exists(".admin-link"));
assert.ok(exists(".review"));
assert.ok(!exists(".settings-link"));
});
test("staff menu - admin", async function (assert) {
this.currentUser.setProperties({ admin: true });
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(exists(".settings-link"));
});
test("logged in links", async function (assert) {
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(exists(".new-topics-link"));
assert.ok(exists(".unread-topics-link"));
});
test("general links", async function (assert) {
this.owner.unregister("current-user:main");
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(!exists("li[class='']"));
assert.ok(exists(".latest-topics-link"));
assert.ok(!exists(".new-topics-link"));
assert.ok(!exists(".unread-topics-link"));
assert.ok(exists(".top-topics-link"));
assert.ok(exists(".badge-link"));
assert.ok(exists(".category-link"));
assert.ok(exists(".about-link"));
assert.ok(exists(".keyboard-shortcuts-link"));
});
let maxCategoriesToDisplay;
test("top categories - anonymous", async function (assert) {
this.owner.unregister("current-user:main");
this.siteSettings.header_dropdown_category_count = 8;
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.strictEqual(count(".category-link"), 8);
assert.deepEqual(
[...queryAll(".category-link .category-name")].map((el) => el.innerText),
this.site
.get("categoriesByCount")
.slice(0, 8)
.map((c) => c.name)
);
});
test("top categories - allow_uncategorized_topics", async function (assert) {
this.owner.unregister("current-user:main");
this.siteSettings.allow_uncategorized_topics = false;
this.siteSettings.header_dropdown_category_count = 8;
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.strictEqual(count(".category-link"), 8);
assert.deepEqual(
[...queryAll(".category-link .category-name")].map((el) => el.innerText),
this.site
.get("categoriesByCount")
.filter((c) => c.name !== "uncategorized")
.slice(0, 8)
.map((c) => c.name)
);
});
test("top categories", async function (assert) {
this.siteSettings.header_dropdown_category_count = 8;
maxCategoriesToDisplay = this.siteSettings.header_dropdown_category_count;
categoriesByCount = this.site.get("categoriesByCount").slice();
categoriesByCount.every((c) => {
if (!topCategoryIds.includes(c.id)) {
if (mutedCategoryIds.length === 0) {
mutedCategoryIds.push(c.id);
c.set("notification_level", NotificationLevels.MUTED);
} else if (unreadCategoryIds.length === 0) {
unreadCategoryIds.push(c.id);
for (let i = 0; i < 5; i++) {
c.topicTrackingState.modifyState(123 + i, {
category_id: c.id,
last_read_post_number: 1,
highest_post_number: 2,
notification_level: NotificationLevels.TRACKING,
unread_not_too_old: true,
});
}
} else {
unreadCategoryIds.splice(0, 0, c.id);
for (let i = 0; i < 10; i++) {
c.topicTrackingState.modifyState(321 + i, {
category_id: c.id,
last_read_post_number: null,
created_in_new_period: true,
});
}
return false;
}
}
return true;
});
this.currentUser.set("top_category_ids", topCategoryIds);
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.strictEqual(
count(".category-link"),
maxCategoriesToDisplay,
"categories displayed limited by header_dropdown_category_count"
);
categoriesByCount = categoriesByCount.filter(
(c) => !mutedCategoryIds.includes(c.id)
);
let ids = [
...unreadCategoryIds,
...topCategoryIds,
...categoriesByCount.map((c) => c.id),
]
.uniq()
.slice(0, maxCategoriesToDisplay);
assert.deepEqual(
[...queryAll(".category-link .category-name")].map((el) => el.innerText),
ids.map(
(id) => categoriesByCount.find((category) => category.id === id).name
),
"top categories are in the correct order"
);
});
test("badges link - disabled", async function (assert) {
this.siteSettings.enable_badges = false;
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(!exists(".badge-link"));
});
test("badges link", async function (assert) {
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(exists(".badge-link"));
});
test("user directory link", async function (assert) {
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(exists(".user-directory-link"));
});
test("user directory link - disabled", async function (assert) {
this.siteSettings.enable_user_directory = false;
await render(hbs`<MountWidget @widget="hamburger-menu" />`);
assert.ok(!exists(".user-directory-link"));
});
});

View File

@ -0,0 +1,85 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | header", function (hooks) {
setupRenderingTest(hooks);
test("rendering basics", async function (assert) {
await render(hbs`<MountWidget @widget="header" />`);
assert.ok(exists("header.d-header"));
assert.ok(exists("#site-logo"));
});
test("sign up / login buttons", async function (assert) {
this.owner.unregister("current-user:main");
this.set("args", { canSignUp: true });
this.set("showCreateAccount", () => (this.signupShown = true));
this.set("showLogin", () => (this.loginShown = true));
await render(hbs`
<MountWidget
@widget="header"
@showCreateAccount={{this.showCreateAccount}}
@showLogin={{this.showLogin}}
@args={{this.args}}
/>
`);
assert.ok(exists("button.sign-up-button"));
assert.ok(exists("button.login-button"));
await click("button.sign-up-button");
assert.ok(this.signupShown);
await click("button.login-button");
assert.ok(this.loginShown);
});
test("anon when login required", async function (assert) {
this.owner.unregister("current-user:main");
this.set("args", { canSignUp: true });
this.set("showCreateAccount", () => (this.signupShown = true));
this.set("showLogin", () => (this.loginShown = true));
this.siteSettings.login_required = true;
await render(hbs`
<MountWidget
@widget="header"
@showCreateAccount={{this.showCreateAccount}}
@showLogin={{this.showLogin}}
@args={{this.args}}
/>
`);
assert.ok(exists("button.login-button"));
assert.ok(exists("button.sign-up-button"));
assert.ok(!exists("#search-button"));
assert.ok(!exists("#toggle-hamburger-menu"));
});
test("logged in when login required", async function (assert) {
this.set("args", { canSignUp: true });
this.set("showCreateAccount", () => (this.signupShown = true));
this.set("showLogin", () => (this.loginShown = true));
this.siteSettings.login_required = true;
await render(hbs`
<MountWidget
@widget="header"
@showCreateAccount={{this.showCreateAccount}}
@showLogin={{this.showLogin}}
@args={{this.args}}
/>
`);
assert.ok(!exists("button.login-button"));
assert.ok(!exists("button.sign-up-button"));
assert.ok(exists("#search-button"));
assert.ok(exists("#toggle-hamburger-menu"));
assert.ok(exists("#current-user"));
});
});

View File

@ -0,0 +1,194 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import Session from "discourse/models/session";
const bigLogo = "/images/d-logo-sketch.png?test";
const smallLogo = "/images/d-logo-sketch-small.png?test";
const mobileLogo = "/images/d-logo-sketch.png?mobile";
const darkLogo = "/images/d-logo-sketch.png?dark";
const title = "Cool Forum";
const prefersDark = "(prefers-color-scheme: dark)";
module("Integration | Component | Widget | home-logo", function (hooks) {
setupRenderingTest(hooks);
hooks.afterEach(function () {
Session.currentProp("darkModeAvailable", null);
Session.currentProp("defaultColorSchemeIsDark", null);
});
test("basics", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_small_url = smallLogo;
this.siteSettings.title = title;
this.set("args", { minimized: false });
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count(".title"), 1);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
assert.strictEqual(query("#site-logo").getAttribute("alt"), title);
});
test("basics - minimized", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_small_url = smallLogo;
this.siteSettings.title = title;
this.set("args", { minimized: true });
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img.logo-small"), 1);
assert.strictEqual(query("img.logo-small").getAttribute("src"), smallLogo);
assert.strictEqual(query("img.logo-small").getAttribute("alt"), title);
assert.strictEqual(query("img.logo-small").getAttribute("width"), "36");
});
test("no logo", async function (assert) {
this.siteSettings.site_logo_url = "";
this.siteSettings.site_logo_small_url = "";
this.siteSettings.title = title;
this.set("args", { minimized: false });
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("h1#site-text-logo.text-logo"), 1);
assert.strictEqual(query("#site-text-logo").innerText, title);
});
test("no logo - minimized", async function (assert) {
this.siteSettings.site_logo_url = "";
this.siteSettings.site_logo_small_url = "";
this.siteSettings.title = title;
this.set("args", { minimized: true });
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count(".d-icon-home"), 1);
});
test("mobile logo", async function (assert) {
this.siteSettings.site_mobile_logo_url = mobileLogo;
this.siteSettings.site_logo_small_url = smallLogo;
this.site.mobileView = true;
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-mobile"), 1);
assert.strictEqual(query("#site-logo").getAttribute("src"), mobileLogo);
});
test("mobile without logo", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.site.mobileView = true;
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
});
test("logo with dark mode alternative", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_dark_url = darkLogo;
Session.currentProp("darkModeAvailable", true);
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
assert.strictEqual(
query("picture source").getAttribute("media"),
prefersDark,
"includes dark mode media attribute"
);
assert.strictEqual(
query("picture source").getAttribute("srcset"),
darkLogo,
"includes dark mode alternative logo source"
);
});
test("mobile logo with dark mode alternative", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_mobile_logo_url = mobileLogo;
this.siteSettings.site_mobile_logo_dark_url = darkLogo;
Session.currentProp("darkModeAvailable", true);
this.site.mobileView = true;
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(query("#site-logo").getAttribute("src"), mobileLogo);
assert.strictEqual(
query("picture source").getAttribute("media"),
prefersDark,
"includes dark mode media attribute"
);
assert.strictEqual(
query("picture source").getAttribute("srcset"),
darkLogo,
"includes dark mode alternative logo source"
);
});
test("dark mode enabled but no dark logo set", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_dark_url = "";
Session.currentProp("darkModeAvailable", true);
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
assert.ok(!exists("picture"), "does not include alternative logo");
});
test("dark logo set but no dark mode", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_dark_url = darkLogo;
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
assert.ok(!exists("picture"), "does not include alternative logo");
});
test("dark color scheme and dark logo set", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_dark_url = darkLogo;
Session.currentProp("defaultColorSchemeIsDark", true);
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(
query("#site-logo").getAttribute("src"),
darkLogo,
"uses dark logo"
);
assert.ok(!exists("picture"), "does not add dark mode alternative");
});
test("dark color scheme and dark logo not set", async function (assert) {
this.siteSettings.site_logo_url = bigLogo;
this.siteSettings.site_logo_dark_url = "";
Session.currentProp("defaultColorSchemeIsDark", true);
await render(hbs`<MountWidget @widget="home-logo" @args={{this.args}} />`);
assert.strictEqual(count("img#site-logo.logo-big"), 1);
assert.strictEqual(
query("#site-logo").getAttribute("src"),
bigLogo,
"uses regular logo on dark scheme if no dark logo"
);
});
});

View File

@ -0,0 +1,85 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { count } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | post-links", function (hooks) {
setupRenderingTest(hooks);
test("duplicate links", async function (assert) {
this.set("args", {
id: 2,
links: [
{
title: "Evil Trout Link",
url: "http://eviltrout.com",
reflection: true,
},
{
title: "Evil Trout Link",
url: "http://dupe.eviltrout.com",
reflection: true,
},
],
});
await render(hbs`<MountWidget @widget="post-links" @args={{this.args}} />`);
assert.strictEqual(
count(".post-links a.track-link"),
1,
"it hides the dupe link"
);
});
test("collapsed links", async function (assert) {
this.set("args", {
id: 1,
links: [
{
title: "Link 1",
url: "http://eviltrout.com?1",
reflection: true,
},
{
title: "Link 2",
url: "http://eviltrout.com?2",
reflection: true,
},
{
title: "Link 3",
url: "http://eviltrout.com?3",
reflection: true,
},
{
title: "Link 4",
url: "http://eviltrout.com?4",
reflection: true,
},
{
title: "Link 5",
url: "http://eviltrout.com?5",
reflection: true,
},
{
title: "Link 6",
url: "http://eviltrout.com?6",
reflection: true,
},
{
title: "Link 7",
url: "http://eviltrout.com?7",
reflection: true,
},
],
});
await render(hbs`<MountWidget @widget="post-links" @args={{this.args}} />`);
assert.strictEqual(count(".expand-links"), 1, "collapsed by default");
await click("a.expand-links");
assert.strictEqual(count(".post-links a.track-link"), 7);
});
});

View File

@ -0,0 +1,78 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count, exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import { resetPostMenuExtraButtons } from "discourse/widgets/post-menu";
import { withPluginApi } from "discourse/lib/plugin-api";
module("Integration | Component | Widget | post-menu", function (hooks) {
setupRenderingTest(hooks);
hooks.afterEach(function () {
resetPostMenuExtraButtons();
});
test("add extra button", async function (assert) {
this.set("args", {});
withPluginApi("0.14.0", (api) => {
api.addPostMenuButton("coffee", () => {
return {
action: "drinkCoffee",
icon: "coffee",
className: "hot-coffee",
title: "coffee.title",
position: "first",
};
});
});
await render(hbs`<MountWidget @widget="post-menu" @args={{this.args}} />`);
assert.strictEqual(
count(".actions .extra-buttons .hot-coffee"),
1,
"It renders extra button"
);
});
test("removes button based on callback", async function (assert) {
this.set("args", { canCreatePost: true, canRemoveReply: true });
withPluginApi("0.14.0", (api) => {
api.removePostMenuButton("reply", (attrs) => {
return attrs.canRemoveReply;
});
});
await render(hbs`<MountWidget @widget="post-menu" @args={{this.args}} />`);
assert.ok(!exists(".actions .reply"), "it removes reply button");
});
test("does not remove button", async function (assert) {
this.set("args", { canCreatePost: true, canRemoveReply: false });
withPluginApi("0.14.0", (api) => {
api.removePostMenuButton("reply", (attrs) => {
return attrs.canRemoveReply;
});
});
await render(hbs`<MountWidget @widget="post-menu" @args={{this.args}} />`);
assert.ok(exists(".actions .reply"), "it does not remove reply button");
});
test("removes button", async function (assert) {
this.set("args", { canCreatePost: true });
withPluginApi("0.14.0", (api) => {
api.removePostMenuButton("reply");
});
await render(hbs`<MountWidget @widget="post-menu" @args={{this.args}} />`);
assert.ok(!exists(".actions .reply"), "it removes reply button");
});
});

View File

@ -0,0 +1,93 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module(
"Integration | Component | Widget | post-small-action",
function (hooks) {
setupRenderingTest(hooks);
test("does not have delete/edit/recover buttons by default", async function (assert) {
this.set("args", { id: 123 });
await render(
hbs`<MountWidget @widget="post-small-action" @args={{this.args}} />`
);
assert.ok(!exists(".small-action-desc > .small-action-delete"));
assert.ok(!exists(".small-action-desc > .small-action-recover"));
assert.ok(!exists(".small-action-desc > .small-action-edit"));
});
test("shows edit button if canEdit", async function (assert) {
this.set("args", { id: 123, canEdit: true });
await render(
hbs`<MountWidget @widget="post-small-action" @args={{this.args}} />`
);
assert.ok(
exists(".small-action-desc > .small-action-edit"),
"it adds the edit small action button"
);
});
test("uses custom widget if actionDescriptionWidget", async function (assert) {
this.set("args", { id: 123, actionDescriptionWidget: "button" });
await render(
hbs`<MountWidget @widget="post-small-action" @args={{this.args}} />`
);
assert.ok(
exists(".small-action .widget-button"),
"it adds the custom widget"
);
});
test("does not show edit button if canRecover even if canEdit", async function (assert) {
this.set("args", { id: 123, canEdit: true, canRecover: true });
await render(
hbs`<MountWidget @widget="post-small-action" @args={{this.args}} />`
);
assert.ok(
!exists(".small-action-desc > .small-action-edit"),
"it does not add the edit small action button"
);
assert.ok(
exists(".small-action-desc > .small-action-recover"),
"it adds the recover small action button"
);
});
test("shows delete button if canDelete", async function (assert) {
this.set("args", { id: 123, canDelete: true });
await render(
hbs`<MountWidget @widget="post-small-action" @args={{this.args}} />`
);
assert.ok(
exists(".small-action-desc > .small-action-delete"),
"it adds the delete small action button"
);
});
test("shows undo button if canRecover", async function (assert) {
this.set("args", { id: 123, canRecover: true });
await render(
hbs`<MountWidget @widget="post-small-action" @args={{this.args}} />`
);
assert.ok(
exists(".small-action-desc > .small-action-recover"),
"it adds the recover small action button"
);
});
}
);

View File

@ -0,0 +1,154 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import Post from "discourse/models/post";
import Topic from "discourse/models/topic";
function postStreamTest(name, attrs) {
test(name, async function (assert) {
const site = this.container.lookup("site:main");
let posts = attrs.posts.call(this);
posts.forEach((p) => p.set("site", site));
this.set("posts", posts);
await render(
hbs`<MountWidget @widget="post-stream" @args={{hash posts=this.posts}} />`
);
attrs.test.call(this, assert);
});
}
module("Integration | Component | Widget | post-stream", function (hooks) {
setupRenderingTest(hooks);
postStreamTest("basics", {
posts() {
const site = this.container.lookup("site:main");
const topic = Topic.create();
topic.set("details.created_by", { id: 123 });
return [
Post.create({
topic,
id: 1,
post_number: 1,
user_id: 123,
primary_group_name: "trout",
avatar_template: "/images/avatar.png",
}),
Post.create({
topic,
id: 2,
post_number: 2,
post_type: site.get("post_types.moderator_action"),
}),
Post.create({ topic, id: 3, post_number: 3, hidden: true }),
Post.create({
topic,
id: 4,
post_number: 4,
post_type: site.get("post_types.whisper"),
}),
Post.create({
topic,
id: 5,
post_number: 5,
wiki: true,
via_email: true,
}),
Post.create({
topic,
id: 6,
post_number: 6,
via_email: true,
is_auto_generated: true,
}),
];
},
test(assert) {
assert.strictEqual(count(".post-stream"), 1);
assert.strictEqual(count(".topic-post"), 6, "renders all posts");
// look for special class bindings
assert.strictEqual(
count(".topic-post:nth-of-type(1).topic-owner"),
1,
"it applies the topic owner class"
);
assert.strictEqual(
count(".topic-post:nth-of-type(1).group-trout"),
1,
"it applies the primary group class"
);
assert.strictEqual(
count(".topic-post:nth-of-type(1).regular"),
1,
"it applies the regular class"
);
assert.strictEqual(
count(".topic-post:nth-of-type(2).moderator"),
1,
"it applies the moderator class"
);
assert.strictEqual(
count(".topic-post:nth-of-type(3).post-hidden"),
1,
"it applies the hidden class"
);
assert.strictEqual(
count(".topic-post:nth-of-type(4).whisper"),
1,
"it applies the whisper class"
);
assert.strictEqual(
count(".topic-post:nth-of-type(5).wiki"),
1,
"it applies the wiki class"
);
// it renders an article for the body with appropriate attributes
assert.strictEqual(count("article#post_2"), 1);
assert.strictEqual(count('article[data-user-id="123"]'), 1);
assert.strictEqual(count('article[data-post-id="3"]'), 1);
assert.strictEqual(count("article#post_5.via-email"), 1);
assert.strictEqual(count("article#post_6.is-auto-generated"), 1);
assert.strictEqual(
count("article:nth-of-type(1) .main-avatar"),
1,
"renders the main avatar"
);
},
});
postStreamTest("deleted posts", {
posts() {
const topic = Topic.create();
topic.set("details.created_by", { id: 123 });
return [
Post.create({
topic,
id: 1,
post_number: 1,
deleted_at: new Date().toString(),
}),
];
},
test(assert) {
assert.strictEqual(
count(".topic-post.deleted"),
1,
"it applies the deleted class"
);
assert.strictEqual(
count(".deleted-user-avatar"),
1,
"it has the trash avatar"
);
},
});
});

View File

@ -0,0 +1,920 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import {
count,
exists,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import EmberObject from "@ember/object";
import I18n from "I18n";
import createStore from "discourse/tests/helpers/create-store";
module("Integration | Component | Widget | post", function (hooks) {
setupRenderingTest(hooks);
test("basic elements", async function (assert) {
this.set("args", { shareUrl: "/example", post_number: 1 });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(exists(".names"), "includes poster name");
assert.ok(exists("a.post-date"), "includes post date");
});
test("post - links", async function (assert) {
this.set("args", {
cooked:
"<a href='http://link1.example.com/'>first link</a> and <a href='http://link2.example.com/?some=query'>second link</a>",
linkCounts: [
{ url: "http://link1.example.com/", clicks: 1, internal: true },
{ url: "http://link2.example.com/", clicks: 2, internal: true },
],
});
await render(
hbs`<MountWidget @widget="post-contents" @args={{this.args}} />`
);
assert.strictEqual(queryAll(".badge.clicks")[0].innerText, "1");
assert.strictEqual(queryAll(".badge.clicks")[1].innerText, "2");
});
test("post - onebox links", async function (assert) {
this.set("args", {
cooked: `
<p><a href="https://example.com">Other URL</a></p>
<aside class="onebox twitterstatus" data-onebox-src="https://twitter.com/codinghorror">
<header class="source">
<a href="https://twitter.com/codinghorror" target="_blank" rel="noopener">twitter.com</a>
</header>
<article class="onebox-body">
<h4><a href="https://twitter.com/codinghorror" target="_blank" rel="noopener">Jeff Atwood</a></h4>
<div class="twitter-screen-name"><a href="https://twitter.com/codinghorror" target="_blank" rel="noopener">@codinghorror</a></div>
</article>
</aside>`,
linkCounts: [
{ url: "https://example.com", clicks: 1 },
{ url: "https://twitter.com/codinghorror", clicks: 2 },
],
});
await render(
hbs`<MountWidget @widget="post-contents" @args={{this.args}} />`
);
assert.strictEqual(count(".badge.clicks"), 2);
assert.strictEqual(queryAll(".badge.clicks")[0].innerText, "1");
assert.strictEqual(queryAll(".badge.clicks")[1].innerText, "2");
});
test("wiki", async function (assert) {
this.set("args", { wiki: true, version: 2, canViewEditHistory: true });
this.set("showHistory", () => (this.historyShown = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @showHistory={{this.showHistory}} />
`);
await click(".post-info .wiki");
assert.ok(
this.historyShown,
"clicking the wiki icon displays the post history"
);
});
test("wiki without revision", async function (assert) {
this.set("args", { wiki: true, version: 1, canViewEditHistory: true });
this.set("editPost", () => (this.editPostCalled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @editPost={{this.editPost}} />
`);
await click(".post-info .wiki");
assert.ok(this.editPostCalled, "clicking wiki icon edits the post");
});
test("via-email", async function (assert) {
this.set("args", { via_email: true, canViewRawEmail: true });
this.set("showRawEmail", () => (this.rawEmailShown = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @showRawEmail={{this.showRawEmail}} />
`);
await click(".post-info.via-email");
assert.ok(this.rawEmailShown, "clicking the envelope shows the raw email");
});
test("via-email without permission", async function (assert) {
this.set("args", { via_email: true, canViewRawEmail: false });
this.set("showRawEmail", () => (this.rawEmailShown = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @showRawEmail={{this.showRawEmail}} />
`);
await click(".post-info.via-email");
assert.ok(
!this.rawEmailShown,
"clicking the envelope doesn't show the raw email"
);
});
test("history", async function (assert) {
this.set("args", { version: 3, canViewEditHistory: true });
this.set("showHistory", () => (this.historyShown = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @showHistory={{this.showHistory}} />
`);
await click(".post-info.edits button");
assert.ok(this.historyShown, "clicking the pencil shows the history");
});
test("history without view permission", async function (assert) {
this.set("args", { version: 3, canViewEditHistory: false });
this.set("showHistory", () => (this.historyShown = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @showHistory={{this.showHistory}} />
`);
await click(".post-info.edits");
assert.ok(
!this.historyShown,
`clicking the pencil doesn't show the history`
);
});
test("whisper", async function (assert) {
this.set("args", { isWhisper: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(count(".topic-post.whisper"), 1);
assert.strictEqual(count(".post-info.whisper"), 1);
});
test("like count button", async function (assert) {
const store = createStore();
const topic = store.createRecord("topic", { id: 123 });
const post = store.createRecord("post", {
id: 1,
post_number: 1,
topic,
like_count: 3,
actions_summary: [{ id: 2, count: 1, hidden: false, can_act: true }],
});
this.set("post", post);
this.set("args", { likeCount: 1 });
await render(
hbs`<MountWidget @widget="post" @model={{this.post}} @args={{this.args}} />`
);
assert.strictEqual(count("button.like-count"), 1);
assert.ok(!exists(".who-liked"));
// toggle it on
await click("button.like-count");
assert.strictEqual(count(".who-liked"), 1);
assert.strictEqual(count(".who-liked a.trigger-user-card"), 1);
// toggle it off
await click("button.like-count");
assert.ok(!exists(".who-liked"));
assert.ok(!exists(".who-liked a.trigger-user-card"));
});
test(`like count with no likes`, async function (assert) {
this.set("args", { likeCount: 0 });
await render(
hbs`<MountWidget @widget="post" @model={{this.post}} @args={{this.args}} />`
);
assert.ok(!exists("button.like-count"));
});
test("share button", async function (assert) {
this.set("args", { shareUrl: "http://share-me.example.com" });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(exists(".actions button.share"), "it renders a share button");
});
test("liking", async function (assert) {
const args = { showLike: true, canToggleLike: true, id: 5 };
this.set("args", args);
this.set("toggleLike", () => {
args.liked = !args.liked;
args.likeCount = args.liked ? 1 : 0;
});
await render(hbs`
<MountWidget @widget="post-menu" @args={{this.args}} @toggleLike={{this.toggleLike}} />
`);
assert.ok(exists(".actions button.like"));
assert.ok(!exists(".actions button.like-count"));
await click(".actions button.like");
assert.ok(!exists(".actions button.like"));
assert.ok(exists(".actions button.has-like"));
assert.strictEqual(count(".actions button.like-count"), 1);
await click(".actions button.has-like");
assert.ok(exists(".actions button.like"));
assert.ok(!exists(".actions button.has-like"));
assert.ok(!exists(".actions button.like-count"));
});
test("anon liking", async function (assert) {
this.owner.unregister("current-user:main");
const args = { showLike: true };
this.set("args", args);
this.set("showLogin", () => (this.loginShown = true));
await render(hbs`
<MountWidget @widget="post-menu" @args={{this.args}} @showLogin={{this.showLogin}} />
`);
assert.ok(exists(".actions button.like"));
assert.ok(!exists(".actions button.like-count"));
assert.strictEqual(
query("button.like").getAttribute("title"),
I18n.t("post.controls.like"),
`shows the right button title for anonymous users`
);
await click(".actions button.like");
assert.ok(this.loginShown);
});
test("edit button", async function (assert) {
this.set("args", { canEdit: true });
this.set("editPost", () => (this.editPostCalled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @editPost={{this.editPost}} />
`);
await click("button.edit");
assert.ok(this.editPostCalled, "it triggered the edit action");
});
test(`edit button - can't edit`, async function (assert) {
this.set("args", { canEdit: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.edit"), "button is not displayed");
});
test("recover button", async function (assert) {
this.set("args", { canDelete: true });
this.set("deletePost", () => (this.deletePostCalled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @deletePost={{this.deletePost}} />
`);
await click("button.delete");
assert.ok(this.deletePostCalled, "it triggered the delete action");
});
test("delete topic button", async function (assert) {
this.set("args", { canDeleteTopic: true });
this.set("deletePost", () => (this.deletePostCalled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @deletePost={{this.deletePost}} />
`);
await click("button.delete");
assert.ok(this.deletePostCalled, "it triggered the delete action");
});
test(`delete topic button - can't delete`, async function (assert) {
this.set("args", { canDeleteTopic: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.delete"), `button is not displayed`);
});
test(`delete topic button - can't delete when topic author without permission`, async function (assert) {
this.set("args", {
canDeleteTopic: false,
showFlagDelete: true,
canFlag: true,
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
await click(".show-more-actions");
assert.strictEqual(count("button.create-flag"), 1, `button is displayed`);
assert.strictEqual(count("button.delete"), 1, `button is displayed`);
assert.strictEqual(
query("button.delete").getAttribute("title"),
I18n.t("post.controls.delete_topic_disallowed"),
`shows the right button title for users without permissions`
);
});
test("recover topic button", async function (assert) {
this.set("args", { canRecoverTopic: true });
this.set("recoverPost", () => (this.recovered = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @recoverPost={{this.recoverPost}} />
`);
await click("button.recover");
assert.ok(this.recovered);
});
test(`recover topic button - can't recover`, async function (assert) {
this.set("args", { canRecoverTopic: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.recover"), `button is not displayed`);
});
test("delete post button", async function (assert) {
this.set("args", { canDelete: true, canFlag: true });
this.set("deletePost", () => (this.deletePostCalled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @deletePost={{this.deletePost}} />
`);
await click(".show-more-actions");
await click("button.delete");
assert.ok(this.deletePostCalled, "it triggered the delete action");
});
test(`delete post button - can't delete`, async function (assert) {
this.set("args", { canDelete: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.delete"), `button is not displayed`);
});
test(`delete post button - can't delete, can't flag`, async function (assert) {
this.set("args", {
canDeleteTopic: false,
showFlagDelete: false,
canFlag: false,
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.delete"), `delete button is not displayed`);
assert.ok(!exists("button.create-flag"), `flag button is not displayed`);
});
test("recover post button", async function (assert) {
this.set("args", { canRecover: true });
this.set("recoverPost", () => (this.recovered = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @recoverPost={{this.recoverPost}} />
`);
await click("button.recover");
assert.ok(this.recovered);
});
test(`recover post button - can't recover`, async function (assert) {
this.set("args", { canRecover: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.recover"), `button is not displayed`);
});
test(`flagging`, async function (assert) {
this.set("args", { canFlag: true });
this.set("showFlags", () => (this.flagsShown = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @showFlags={{this.showFlags}} />
`);
assert.strictEqual(count("button.create-flag"), 1);
await click("button.create-flag");
assert.ok(this.flagsShown, "it triggered the action");
});
test(`flagging: can't flag`, async function (assert) {
this.set("args", { canFlag: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.create-flag"));
});
test(`flagging: can't flag when post is hidden`, async function (assert) {
this.set("args", { canFlag: true, hidden: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.create-flag"));
});
test(`read indicator`, async function (assert) {
this.set("args", { read: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(exists(".read-state.read"));
});
test(`unread indicator`, async function (assert) {
this.set("args", { read: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(exists(".read-state"));
});
test("reply directly above (suppressed)", async function (assert) {
this.set("args", {
replyToUsername: "eviltrout",
replyToAvatarTemplate: "/images/avatar.png",
replyDirectlyAbove: true,
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("a.reply-to-tab"), "hides the tab");
assert.ok(!exists(".avoid-tab"), "doesn't have the avoid tab class");
});
test("reply a few posts above (suppressed)", async function (assert) {
this.set("args", {
replyToUsername: "eviltrout",
replyToAvatarTemplate: "/images/avatar.png",
replyDirectlyAbove: false,
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(exists("a.reply-to-tab"), "shows the tab");
assert.strictEqual(count(".avoid-tab"), 1, "has the avoid tab class");
});
test("reply directly above", async function (assert) {
this.set("args", {
replyToUsername: "eviltrout",
replyToAvatarTemplate: "/images/avatar.png",
replyDirectlyAbove: true,
});
this.siteSettings.suppress_reply_directly_above = false;
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(count(".avoid-tab"), 1, "has the avoid tab class");
await click("a.reply-to-tab");
assert.strictEqual(count("section.embedded-posts.top .cooked"), 1);
assert.strictEqual(count("section.embedded-posts .d-icon-arrow-up"), 1);
});
test("cooked content hidden", async function (assert) {
this.set("args", { cooked_hidden: true });
this.set("expandHidden", () => (this.unhidden = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @expandHidden={{this.expandHidden}} />
`);
await click(".topic-body .expand-hidden");
assert.ok(this.unhidden, "triggers the action");
});
test("expand first post", async function (assert) {
const store = createStore();
this.set("args", { expandablePost: true });
this.set("post", store.createRecord("post", { id: 1234 }));
await render(
hbs`<MountWidget @widget="post" @model={{this.post}} @args={{this.args}} />`
);
await click(".topic-body .expand-post");
assert.ok(!exists(".expand-post"), "button is gone");
});
test("can't bookmark", async function (assert) {
this.set("args", { canBookmark: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.bookmark"));
assert.ok(!exists("button.bookmarked"));
});
test("bookmark", async function (assert) {
const args = { canBookmark: true };
this.set("args", args);
this.set("toggleBookmark", () => (args.bookmarked = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @toggleBookmark={{this.toggleBookmark}} />
`);
assert.strictEqual(count(".post-menu-area .bookmark"), 1);
assert.ok(!exists("button.bookmarked"));
});
test("can't show admin menu when you can't manage", async function (assert) {
this.set("args", { canManage: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists(".post-menu-area .show-post-admin-menu"));
});
test("show admin menu", async function (assert) {
this.set("args", { canManage: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists(".post-admin-menu"));
await click(".post-menu-area .show-post-admin-menu");
assert.strictEqual(count(".post-admin-menu"), 1, "it shows the popup");
await click(".post-menu-area");
assert.ok(!exists(".post-admin-menu"), "clicking outside clears the popup");
});
test("permanently delete topic", async function (assert) {
this.set("args", { canManage: true, canPermanentlyDelete: true });
this.set("permanentlyDeletePost", () => (this.deleted = true));
await render(
hbs`<MountWidget @widget="post" @args={{this.args}} @permanentlyDeletePost={{this.permanentlyDeletePost}} />`
);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .permanently-delete");
assert.ok(this.deleted);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("permanently delete post", async function (assert) {
this.set("args", { canManage: true, canPermanentlyDelete: true });
this.set("permanentlyDeletePost", () => (this.deleted = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @permanentlyDeletePost={{this.permanentlyDeletePost}} />
`);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .permanently-delete");
assert.ok(this.deleted);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("toggle moderator post", async function (assert) {
this.currentUser.set("moderator", true);
this.set("args", { canManage: true });
this.set("togglePostType", () => (this.toggled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @togglePostType={{this.togglePostType}} />
`);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .toggle-post-type");
assert.ok(this.toggled);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("toggle moderator post", async function (assert) {
this.currentUser.set("moderator", true);
this.set("args", { canManage: true });
this.set("togglePostType", () => (this.toggled = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @togglePostType={{this.togglePostType}} />
`);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .toggle-post-type");
assert.ok(this.toggled);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("rebake post", async function (assert) {
this.set("args", { canManage: true });
this.set("rebakePost", () => (this.baked = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @rebakePost={{this.rebakePost}} />
`);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .rebuild-html");
assert.ok(this.baked);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("unhide post", async function (assert) {
this.currentUser.admin = true;
this.set("args", { canManage: true, hidden: true });
this.set("unhidePost", () => (this.unhidden = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @unhidePost={{this.unhidePost}} />
`);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .unhide-post");
assert.ok(this.unhidden);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("change owner", async function (assert) {
this.currentUser.admin = true;
this.set("args", { canManage: true });
this.set("changePostOwner", () => (this.owned = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @changePostOwner={{this.changePostOwner}} />
`);
await click(".post-menu-area .show-post-admin-menu");
await click(".post-admin-menu .change-owner");
assert.ok(this.owned);
assert.ok(!exists(".post-admin-menu"), "also hides the menu");
});
test("reply", async function (assert) {
this.set("args", { canCreatePost: true });
this.set("replyToPost", () => (this.replied = true));
await render(hbs`
<MountWidget @widget="post" @args={{this.args}} @replyToPost={{this.replyToPost}} />
`);
await click(".post-controls .create");
assert.ok(this.replied);
});
test("reply - without permissions", async function (assert) {
this.set("args", { canCreatePost: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists(".post-controls .create"));
});
test("replies - no replies", async function (assert) {
this.set("args", { replyCount: 0 });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.show-replies"));
});
test("replies - multiple replies", async function (assert) {
this.siteSettings.suppress_reply_directly_below = true;
this.set("args", { replyCount: 2, replyDirectlyBelow: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(count("button.show-replies"), 1);
});
test("replies - one below, suppressed", async function (assert) {
this.siteSettings.suppress_reply_directly_below = true;
this.set("args", { replyCount: 1, replyDirectlyBelow: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists("button.show-replies"));
});
test("replies - one below, not suppressed", async function (assert) {
this.siteSettings.suppress_reply_directly_below = false;
this.set("args", { id: 6654, replyCount: 1, replyDirectlyBelow: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
await click("button.show-replies");
assert.strictEqual(count("section.embedded-posts.bottom .cooked"), 1);
assert.strictEqual(count("section.embedded-posts .d-icon-arrow-down"), 1);
});
test("topic map not shown", async function (assert) {
this.set("args", { showTopicMap: false });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists(".topic-map"));
});
test("topic map - few posts", async function (assert) {
this.set("args", {
showTopicMap: true,
topicPostsCount: 2,
participants: [{ username: "eviltrout" }, { username: "codinghorror" }],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(
!exists("li.avatars a.poster"),
"shows no participants when collapsed"
);
await click("nav.buttons button");
assert.strictEqual(
count(".topic-map-expanded a.poster"),
2,
"shows all when expanded"
);
});
test("topic map - participants", async function (assert) {
this.set("args", {
showTopicMap: true,
topicPostsCount: 10,
participants: [
{ username: "eviltrout" },
{ username: "codinghorror" },
{ username: "sam" },
{ username: "ZogStrIP" },
],
userFilters: ["sam", "codinghorror"],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(
count("li.avatars a.poster"),
3,
"limits to three participants"
);
await click("nav.buttons button");
assert.ok(!exists("li.avatars a.poster"));
assert.strictEqual(
count(".topic-map-expanded a.poster"),
4,
"shows all when expanded"
);
assert.strictEqual(count("a.poster.toggled"), 2, "two are toggled");
});
test("topic map - links", async function (assert) {
this.set("args", {
showTopicMap: true,
topicLinks: [
{ url: "http://link1.example.com", clicks: 0 },
{ url: "http://link2.example.com", clicks: 0 },
{ url: "http://link3.example.com", clicks: 0 },
{ url: "http://link4.example.com", clicks: 0 },
{ url: "http://link5.example.com", clicks: 0 },
{ url: "http://link6.example.com", clicks: 0 },
],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(count(".topic-map"), 1);
assert.strictEqual(count(".map.map-collapsed"), 1);
assert.ok(!exists(".topic-map-expanded"));
await click("nav.buttons button");
assert.ok(!exists(".map.map-collapsed"));
assert.strictEqual(count(".topic-map .d-icon-chevron-up"), 1);
assert.strictEqual(count(".topic-map-expanded"), 1);
assert.strictEqual(
count(".topic-map-expanded .topic-link"),
5,
"it limits the links displayed"
);
await click(".link-summary button");
assert.strictEqual(
count(".topic-map-expanded .topic-link"),
6,
"all links now shown"
);
});
test("topic map - no summary", async function (assert) {
this.set("args", { showTopicMap: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.ok(!exists(".toggle-summary"));
});
test("topic map - has summary", async function (assert) {
this.set("args", { showTopicMap: true, hasTopicSummary: true });
this.set("showSummary", () => (this.summaryToggled = true));
await render(
hbs`<MountWidget @widget="post" @args={{this.args}} @showSummary={{this.showSummary}} />`
);
assert.strictEqual(count(".toggle-summary"), 1);
await click(".toggle-summary button");
assert.ok(this.summaryToggled);
});
test("pm map", async function (assert) {
this.set("args", {
showTopicMap: true,
showPMMap: true,
allowedGroups: [],
allowedUsers: [EmberObject.create({ username: "eviltrout" })],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(count(".private-message-map"), 1);
assert.strictEqual(count(".private-message-map .user"), 1);
});
test("post notice - with username", async function (assert) {
const twoDaysAgo = new Date();
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
this.siteSettings.display_name_on_posts = false;
this.siteSettings.prioritize_username_in_ux = true;
this.siteSettings.old_post_notice_days = 14;
this.set("args", {
username: "codinghorror",
name: "Jeff",
created_at: new Date(),
notice: {
type: "returning_user",
lastPostedAt: twoDaysAgo,
},
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(
query(".post-notice.returning-user:not(.old)").innerText.trim(),
I18n.t("post.notice.returning_user", {
user: "codinghorror",
time: "2 days ago",
})
);
});
test("post notice - with name", async function (assert) {
this.siteSettings.display_name_on_posts = true;
this.siteSettings.prioritize_username_in_ux = false;
this.siteSettings.old_post_notice_days = 14;
this.set("args", {
username: "codinghorror",
name: "Jeff",
created_at: new Date(2019, 0, 1),
notice: { type: "new_user" },
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.strictEqual(
query(".post-notice.old.new-user").innerText.trim(),
I18n.t("post.notice.new_user", { user: "Jeff", time: "Jan '10" })
);
});
test("show group request in post", async function (assert) {
this.set("args", {
username: "foo",
requestedGroupName: "testGroup",
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
const link = query(".group-request a");
assert.strictEqual(link.innerText.trim(), I18n.t("groups.requests.handle"));
assert.strictEqual(
link.getAttribute("href"),
"/g/testGroup/requests?filter=foo"
);
});
});

View File

@ -0,0 +1,75 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | poster-name", function (hooks) {
setupRenderingTest(hooks);
test("basic rendering", async function (assert) {
this.set("args", {
username: "eviltrout",
usernameUrl: "/u/eviltrout",
name: "Robin Ward",
user_title: "Trout Master",
});
await render(
hbs`<MountWidget @widget="poster-name" @args={{this.args}} />`
);
assert.ok(exists(".names"));
assert.ok(exists("span.username"));
assert.ok(exists('a[data-user-card="eviltrout"]'));
assert.strictEqual(query(".username a").innerText, "eviltrout");
assert.strictEqual(query(".full-name a").innerText, "Robin Ward");
assert.strictEqual(query(".user-title").innerText, "Trout Master");
});
test("extra classes and glyphs", async function (assert) {
this.set("args", {
username: "eviltrout",
usernameUrl: "/u/eviltrout",
staff: true,
admin: true,
moderator: true,
new_user: true,
primary_group_name: "fish",
});
await render(
hbs`<MountWidget @widget="poster-name" @args={{this.args}} />`
);
assert.ok(exists("span.staff"));
assert.ok(exists("span.admin"));
assert.ok(exists("span.moderator"));
assert.ok(exists(".d-icon-shield-alt"));
assert.ok(exists("span.new-user"));
assert.ok(exists("span.fish"));
});
test("disable display name on posts", async function (assert) {
this.siteSettings.display_name_on_posts = false;
this.set("args", { username: "eviltrout", name: "Robin Ward" });
await render(
hbs`<MountWidget @widget="poster-name" @args={{this.args}} />`
);
assert.ok(!exists(".full-name"));
});
test("doesn't render a name if it's similar to the username", async function (assert) {
this.siteSettings.prioritize_username_in_ux = true;
this.siteSettings.display_name_on_posts = true;
this.set("args", { username: "eviltrout", name: "evil-trout" });
await render(
hbs`<MountWidget @widget="poster-name" @args={{this.args}} />`
);
assert.ok(!exists(".second"));
});
});

View File

@ -0,0 +1,36 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
const CONTENT_DIV_SELECTOR = "li > a > div";
module(
"Integration | Component | Widget | quick-access-item",
function (hooks) {
setupRenderingTest(hooks);
test("content attribute is escaped", async function (assert) {
this.set("args", { content: "<b>bold</b>" });
await render(
hbs`<MountWidget @widget="quick-access-item" @args={{this.args}} />`
);
const contentDiv = query(CONTENT_DIV_SELECTOR);
assert.strictEqual(contentDiv.innerText, "<b>bold</b>");
});
test("escapedContent attribute is not escaped", async function (assert) {
this.set("args", { escapedContent: "&quot;quote&quot;" });
await render(
hbs`<MountWidget @widget="quick-access-item" @args={{this.args}} />`
);
const contentDiv = query(CONTENT_DIV_SELECTOR);
assert.strictEqual(contentDiv.innerText, '"quote"');
});
}
);

View File

@ -0,0 +1,26 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { count, exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module("Integration | Component | Widget | small-user-list", function (hooks) {
setupRenderingTest(hooks);
test("renders avatars and support for unknown", async function (assert) {
this.set("args", {
users: [
{ id: 456, username: "eviltrout" },
{ id: 457, username: "someone", unknown: true },
],
});
await render(
hbs`<MountWidget @widget="small-user-list" @args={{this.args}} />`
);
assert.strictEqual(count('[data-user-card="eviltrout"]'), 1);
assert.ok(!exists('[data-user-card="someone"]'));
assert.ok(exists(".unknown"), "includes unknown user");
});
});

View File

@ -0,0 +1,69 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import Category from "discourse/models/category";
import Topic from "discourse/models/topic";
const createArgs = (topic) => {
return {
topic,
openUpwards: "true",
toggleMultiSelect: () => {},
deleteTopic: () => {},
recoverTopic: () => {},
toggleClosed: () => {},
toggleArchived: () => {},
toggleVisibility: () => {},
showTopicTimerModal: () => {},
showFeatureTopic: () => {},
showChangeTimestamp: () => {},
resetBumpDate: () => {},
convertToPublicTopic: () => {},
convertToPrivateMessage: () => {},
};
};
module(
"Integration | Component | Widget | topic-admin-menu-button",
function (hooks) {
setupRenderingTest(hooks);
test("topic-admin-menu-button is present for admin/moderators", async function (assert) {
this.currentUser.setProperties({
admin: true,
moderator: true,
id: 123,
});
const topic = Topic.create({ user_id: this.currentUser.id });
topic.set("category_id", Category.create({ read_restricted: true }).id);
this.siteSettings.allow_featured_topic_on_user_profiles = true;
this.set("args", createArgs(topic));
await render(
hbs`<MountWidget @widget="topic-admin-menu-button" @args={{this.args}} />`
);
assert.ok(exists(".toggle-admin-menu"), "admin wrench is present");
});
test("topic-admin-menu-button hides for non-admin when there is no action", async function (assert) {
this.currentUser.setProperties({
admin: false,
moderator: false,
id: 123,
});
const topic = Topic.create({ user_id: this.currentUser.id });
topic.set("category_id", Category.create({ read_restricted: true }).id);
this.siteSettings.allow_featured_topic_on_user_profiles = true;
this.set("args", createArgs(topic));
await render(
hbs`<MountWidget @widget="topic-admin-menu-button" @args={{this.args}} />`
);
assert.ok(!exists(".toggle-admin-menu"), "admin wrench is not present");
});
}
);

View File

@ -0,0 +1,55 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { render } from "@ember/test-helpers";
import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
module(
"Integration | Component | Widget | topic-participant",
function (hooks) {
setupRenderingTest(hooks);
test("one post", async function (assert) {
this.set("args", {
username: "test",
avatar_template: "/images/avatar.png",
post_count: 1,
});
await render(
hbs`<MountWidget @widget="topic-participant" @args={{this.args}} />`
);
assert.ok(exists("a.poster.trigger-user-card"));
assert.ok(!exists("span.post-count"), "don't show count for only 1 post");
assert.ok(!exists(".avatar-flair"), "no avatar flair");
});
test("many posts, a primary group with flair", async function (assert) {
this.set("args", {
username: "test",
avatar_template: "/images/avatar.png",
post_count: 2,
primary_group_name: "devs",
flair_name: "devs",
flair_url: "/images/d-logo-sketch-small.png",
flair_bg_color: "222",
});
await render(
hbs`<MountWidget @widget="topic-participant" @args={{this.args}} />`
);
assert.ok(exists("a.poster.trigger-user-card"));
assert.ok(exists("span.post-count"), "show count for many posts");
assert.ok(
exists(".group-devs a.poster"),
"add class for the group outside the link"
);
assert.ok(
exists(".avatar-flair.avatar-flair-devs"),
"show flair with group class"
);
});
}
);

View File

@ -0,0 +1,76 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import TopicStatusIcons from "discourse/helpers/topic-status-icons";
import createStore from "discourse/tests/helpers/create-store";
module("Integration | Component | Widget | topic-status", function (hooks) {
setupRenderingTest(hooks);
test("basics", async function (assert) {
const store = createStore();
this.set("args", {
topic: store.createRecord("topic", { closed: true }),
disableActions: true,
});
await render(
hbs`<MountWidget @widget="topic-status" @args={{this.args}} />`
);
assert.ok(exists(".topic-status .d-icon-lock"));
});
test("extendability", async function (assert) {
const store = createStore();
TopicStatusIcons.addObject([
"has_accepted_answer",
"far-check-square",
"solved",
]);
this.set("args", {
topic: store.createRecord("topic", {
has_accepted_answer: true,
}),
disableActions: true,
});
await render(
hbs`<MountWidget @widget="topic-status" @args={{this.args}} />`
);
assert.ok(exists(".topic-status .d-icon-far-check-square"));
});
test("toggling pin status", async function (assert) {
const store = createStore();
this.set("args", {
topic: store.createRecord("topic", { closed: true, pinned: true }),
});
await render(
hbs`<MountWidget @widget="topic-status" @args={{this.args}} />`
);
assert.ok(exists(".topic-statuses .pinned"), "pinned icon is shown");
assert.ok(
!exists(".topic-statuses .unpinned"),
"unpinned icon is not shown"
);
await click(".topic-statuses .pin-toggle-button");
assert.ok(!exists(".topic-statuses .pinned"), "pinned icon is not shown");
assert.ok(exists(".topic-statuses .unpinned"), "unpinned icon is shown");
await click(".topic-statuses .pin-toggle-button");
assert.ok(exists(".topic-statuses .pinned"), "pinned icon is shown");
assert.ok(
!exists(".topic-statuses .unpinned"),
"unpinned icon is not shown"
);
});
});

View File

@ -0,0 +1,221 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { exists, query, queryAll } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import sinon from "sinon";
import DiscourseURL from "discourse/lib/url";
import I18n from "I18n";
module("Integration | Component | Widget | user-menu", function (hooks) {
setupRenderingTest(hooks);
test("basics", async function (assert) {
await render(hbs`<MountWidget @widget="user-menu" />`);
assert.ok(exists(".user-menu"));
assert.ok(exists(".user-preferences-link"));
assert.ok(exists(".user-notifications-link"));
assert.ok(exists(".user-bookmarks-link"));
assert.ok(exists(".quick-access-panel"));
assert.ok(exists(".notifications-dismiss"));
});
test("notifications", async function (assert) {
await render(hbs`<MountWidget @widget="user-menu" />`);
const links = queryAll(".quick-access-panel li a");
assert.strictEqual(links.length, 6);
assert.ok(links[1].href.includes("/t/a-slug/123"));
assert.ok(
links[2].href.includes(
"/u/eviltrout/notifications/likes-received?acting_username=aquaman"
)
);
assert.strictEqual(
links[2].text,
`aquaman ${I18n.t("notifications.liked_consolidated_description", {
count: 5,
})}`
);
assert.ok(links[3].href.includes("/u/test2/messages/group/test"));
assert.ok(
links[3].innerHTML.includes(
I18n.t("notifications.group_message_summary", {
count: 5,
group_name: "test",
})
)
);
assert.ok(links[4].href.includes("/u/test1"));
assert.ok(
links[4].innerHTML.includes(
I18n.t("notifications.invitee_accepted", { username: "test1" })
)
);
assert.ok(links[5].href.includes("/g/test"));
assert.ok(
links[5].innerHTML.includes(
I18n.t("notifications.membership_request_accepted", {
group_name: "test",
})
)
);
const routeToStub = sinon.stub(DiscourseURL, "routeTo");
await click(".user-notifications-link");
assert.ok(
routeToStub.calledWith(query(".user-notifications-link").dataset.url),
"a second click should redirect to the full notifications page"
);
});
test("log out", async function (assert) {
this.set("logout", () => (this.loggedOut = true));
await render(
hbs`<MountWidget @widget="user-menu" @logout={{this.logout}} />`
);
await click(".user-preferences-link");
assert.ok(exists(".logout"));
await click(".logout button");
assert.ok(this.loggedOut);
});
test("private messages - disabled", async function (assert) {
this.siteSettings.enable_personal_messages = false;
await render(hbs`<MountWidget @widget="user-menu" />`);
assert.ok(!exists(".user-pms-link"));
});
test("private messages - enabled", async function (assert) {
this.siteSettings.enable_personal_messages = true;
await render(hbs`<MountWidget @widget="user-menu" />`);
const userPmsLink = query(".user-pms-link").dataset.url;
assert.ok(userPmsLink);
await click(".user-pms-link");
const message = query(".quick-access-panel li a");
assert.ok(message);
assert.ok(
message.href.includes("/t/bug-can-not-render-emoji-properly/174/2"),
"should link to the next unread post"
);
assert.ok(
message.innerHTML.includes("mixtape"),
"should include the last poster's username"
);
assert.ok(
message.innerHTML.match(/<img.*class="emoji".*>/),
"should correctly render emoji in message title"
);
const routeToStub = sinon.stub(DiscourseURL, "routeTo");
await click(".user-pms-link");
assert.ok(
routeToStub.calledWith(userPmsLink),
"a second click should redirect to the full private messages page"
);
});
test("bookmarks", async function (assert) {
await render(hbs`<MountWidget @widget="user-menu" />`);
await click(".user-bookmarks-link");
const allBookmarks = queryAll(".quick-access-panel li a");
const bookmark = allBookmarks[0];
assert.ok(
bookmark.href.includes("/t/yelling-topic-title/119"),
"the Post bookmark should have a link to the topic"
);
assert.ok(
bookmark.innerHTML.includes("someguy"),
"should include the last poster's username"
);
assert.ok(
bookmark.innerHTML.match(/<img.*class="emoji".*>/),
"should correctly render emoji in bookmark title"
);
assert.ok(
bookmark.innerHTML.includes("d-icon-bookmark"),
"should use the correct icon based on no reminder_at present"
);
const routeToStub = sinon.stub(DiscourseURL, "routeTo");
await click(".user-bookmarks-link");
assert.ok(
routeToStub.calledWith(query(".user-bookmarks-link").dataset.url),
"a second click should redirect to the full bookmarks page"
);
const nonPostBookmarkableBookmark = allBookmarks[1];
assert.ok(
nonPostBookmarkableBookmark.href.includes("chat/message/2437"),
"bookmarkable_type that is not Post or Topic should use bookmarkable_url for the item link"
);
assert.ok(
nonPostBookmarkableBookmark.innerHTML.includes(
"d-icon-discourse-bookmark-clock"
),
"should use the correct icon based on reminder_at present"
);
});
test("anonymous", async function (assert) {
this.currentUser.setProperties({ is_anonymous: false, trust_level: 3 });
this.siteSettings.allow_anonymous_posting = true;
this.siteSettings.anonymous_posting_min_trust_level = 3;
this.set("toggleAnonymous", () => (this.anonymous = true));
await render(hbs`
<MountWidget @widget="user-menu" @toggleAnonymous={{this.toggleAnonymous}} />
`);
await click(".user-preferences-link");
assert.ok(exists(".enable-anonymous"));
await click(".enable-anonymous");
assert.ok(this.anonymous);
});
test("anonymous - disabled", async function (assert) {
this.siteSettings.allow_anonymous_posting = false;
await render(hbs`<MountWidget @widget="user-menu" />`);
await click(".user-preferences-link");
assert.ok(!exists(".enable-anonymous"));
});
test("anonymous - switch back", async function (assert) {
this.currentUser.setProperties({ is_anonymous: true });
this.siteSettings.allow_anonymous_posting = true;
this.set("toggleAnonymous", () => (this.anonymous = false));
await render(hbs`
<MountWidget @widget="user-menu" @toggleAnonymous={{this.toggleAnonymous}} />
`);
await click(".user-preferences-link");
assert.ok(exists(".disable-anonymous"));
await click(".disable-anonymous");
assert.notOk(this.anonymous);
});
});

View File

@ -0,0 +1,280 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n";
import hbs from "htmlbars-inline-precompile";
const DEFAULT_CONTENT = {
content: [
{ id: 1, label: "foo" },
{ id: 2, translatedLabel: "FooBar" },
"separator",
{ id: 3, translatedLabel: "With icon", icon: "times" },
{ id: 4, html: "<b>baz</b>" },
{ id: 5, translatedLabel: "Disabled", disabled: true },
],
label: "foo",
};
async function clickRowById(id) {
await click(`#my-dropdown .widget-dropdown-item.item-${id}`);
}
function rowById(id) {
return query(`#my-dropdown .widget-dropdown-item.item-${id}`);
}
async function toggle() {
await click("#my-dropdown .widget-dropdown-header");
}
function headerLabel() {
return query("#my-dropdown .widget-dropdown-header .label").innerText.trim();
}
function header() {
return query("#my-dropdown .widget-dropdown-header");
}
function body() {
return query("#my-dropdown .widget-dropdown-body");
}
const TEMPLATE = hbs`
<MountWidget
@widget="widget-dropdown"
@args={{hash
id="my-dropdown"
icon=this.icon
label=this.label
class=this.class
translatedLabel=this.translatedLabel
content=this.content
options=this.options
}}
/>
`;
module("Integration | Component | Widget | widget-dropdown", function (hooks) {
setupRenderingTest(hooks);
let _translations = I18n.translations;
hooks.afterEach(function () {
I18n.translations = _translations;
});
test("dropdown id", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
assert.ok(exists("#my-dropdown"));
});
test("label", async function (assert) {
I18n.translations = { en: { js: { foo: "FooBaz" } } };
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
assert.strictEqual(headerLabel(), "FooBaz");
});
test("translatedLabel", async function (assert) {
I18n.translations = { en: { js: { foo: "FooBaz" } } };
this.setProperties(DEFAULT_CONTENT);
this.set("translatedLabel", "BazFoo");
await render(TEMPLATE);
assert.strictEqual(headerLabel(), this.translatedLabel);
});
test("content", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.strictEqual(rowById(1).dataset.id, "1", "it creates rows");
assert.strictEqual(rowById(2).dataset.id, "2", "it creates rows");
assert.strictEqual(rowById(3).dataset.id, "3", "it creates rows");
});
test("onChange action", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("onChange", (item) => (query("#test").innerText = item.id));
await render(hbs`
<div id="test"></div>
<MountWidget
@widget="widget-dropdown"
@args={{hash
id="my-dropdown"
label=this.label
content=this.content
onChange=this.onChange
}}
/>
`);
await toggle();
await clickRowById(2);
assert.strictEqual(
query("#test").innerText,
"2",
"it calls the onChange actions"
);
});
test("can be opened and closed", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
assert.ok(exists("#my-dropdown.closed"));
assert.ok(!exists("#my-dropdown .widget-dropdown-body"));
await toggle();
assert.strictEqual(rowById(2).innerText.trim(), "FooBar");
assert.ok(exists("#my-dropdown.opened"));
assert.ok(exists("#my-dropdown .widget-dropdown-body"));
await toggle();
assert.ok(exists("#my-dropdown.closed"));
assert.ok(!exists("#my-dropdown .widget-dropdown-body"));
});
test("icon", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("icon", "times");
await render(TEMPLATE);
assert.ok(exists(header().querySelector(".d-icon-times")));
});
test("class", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("class", "activated");
await render(TEMPLATE);
assert.ok(exists("#my-dropdown.activated"));
});
test("content with translatedLabel", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.strictEqual(rowById(2).innerText.trim(), "FooBar");
});
test("content with label", async function (assert) {
I18n.translations = { en: { js: { foo: "FooBaz" } } };
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.strictEqual(rowById(1).innerText.trim(), "FooBaz");
});
test("content with icon", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.ok(exists(rowById(3).querySelector(".d-icon-times")));
});
test("content with html", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.strictEqual(rowById(4).innerHTML.trim(), "<span><b>baz</b></span>");
});
test("separator", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.ok(
query(
"#my-dropdown .widget-dropdown-item:nth-child(3)"
).classList.contains("separator")
);
});
test("hides widget if no content", async function (assert) {
this.setProperties({ content: null, label: "foo" });
await render(TEMPLATE);
assert.notOk(exists("#my-dropdown .widget-dropdown-header"));
assert.notOk(exists("#my-dropdown .widget-dropdown-body"));
});
test("headerClass option", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("options", { headerClass: "btn-small and-text" });
await render(TEMPLATE);
assert.ok(header().classList.contains("widget-dropdown-header"));
assert.ok(header().classList.contains("btn-small"));
assert.ok(header().classList.contains("and-text"));
});
test("bodyClass option", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("options", { bodyClass: "gigantic and-yet-small" });
await render(TEMPLATE);
await toggle();
assert.ok(body().classList.contains("widget-dropdown-body"));
assert.ok(body().classList.contains("gigantic"));
assert.ok(body().classList.contains("and-yet-small"));
});
test("caret option", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("options", { caret: true });
await render(TEMPLATE);
assert.ok(
exists("#my-dropdown .widget-dropdown-header .d-icon-caret-down")
);
});
test("disabled widget", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
this.set("options", { disabled: true });
await render(TEMPLATE);
assert.ok(exists("#my-dropdown.disabled"));
await toggle();
assert.strictEqual(rowById(1), null, "it does not display options");
});
test("disabled item", async function (assert) {
this.setProperties(DEFAULT_CONTENT);
await render(TEMPLATE);
await toggle();
assert.ok(exists(".widget-dropdown-item.item-5.disabled"));
});
});

View File

@ -0,0 +1,397 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
import widgetHbs from "discourse/widgets/hbs-compiler";
import I18n from "I18n";
import { Promise } from "rsvp";
import { createWidget } from "discourse/widgets/widget";
import { next } from "@ember/runloop";
import { withPluginApi } from "discourse/lib/plugin-api";
module("Integration | Component | Widget | base", function (hooks) {
setupRenderingTest(hooks);
let _translations = I18n.translations;
hooks.afterEach(function () {
I18n.translations = _translations;
});
test("widget attributes are passed in via args", async function (assert) {
createWidget("hello-test", {
tagName: "div.test",
template: widgetHbs`Hello {{attrs.name}}`,
});
this.set("args", { name: "Robin" });
await render(hbs`<MountWidget @widget="hello-test" @args={{this.args}} />`);
assert.strictEqual(query(".test").innerText, "Hello Robin");
});
test("widget services", async function (assert) {
createWidget("service-test", {
tagName: "div.base-url-test",
services: ["router"],
html() {
return this.router.rootURL;
},
});
await render(hbs`<MountWidget @widget="service-test" />`);
assert.strictEqual(query(".base-url-test").innerText, "/");
});
test("hbs template - no tagName", async function (assert) {
createWidget("hbs-test", {
template: widgetHbs`<div class='test'>Hello {{attrs.name}}</div>`,
});
this.set("args", { name: "Robin" });
await render(hbs`<MountWidget @widget="hbs-test" @args={{this.args}} />`);
assert.strictEqual(query("div.test").innerText, "Hello Robin");
});
test("hbs template - with tagName", async function (assert) {
createWidget("hbs-test", {
tagName: "div.test",
template: widgetHbs`Hello {{attrs.name}}`,
});
this.set("args", { name: "Robin" });
await render(hbs`<MountWidget @widget="hbs-test" @args={{this.args}} />`);
assert.strictEqual(query("div.test").innerText, "Hello Robin");
});
test("hbs template - with data attributes", async function (assert) {
createWidget("hbs-test", {
template: widgetHbs`<div class='my-div' data-my-test='hello world'></div>`,
});
await render(hbs`<MountWidget @widget="hbs-test" @args={{this.args}} />`);
assert.strictEqual(query("div.my-div").dataset.myTest, "hello world");
});
test("buildClasses", async function (assert) {
createWidget("classname-test", {
tagName: "div.test",
buildClasses(attrs) {
return ["static", attrs.dynamic];
},
});
this.set("args", { dynamic: "cool-class" });
await render(
hbs`<MountWidget @widget="classname-test" @args={{this.args}} />`
);
assert.ok(exists(".test.static.cool-class"), "it has all the classes");
});
test("buildAttributes", async function (assert) {
createWidget("attributes-test", {
tagName: "div.test",
buildAttributes(attrs) {
return { "data-evil": "trout", "aria-label": attrs.label };
},
});
this.set("args", { label: "accessibility" });
await render(
hbs`<MountWidget @widget="attributes-test" @args={{this.args}} />`
);
assert.ok(exists('.test[data-evil="trout"]'));
assert.ok(exists('.test[aria-label="accessibility"]'));
});
test("buildId", async function (assert) {
createWidget("id-test", {
buildId(attrs) {
return `test-${attrs.id}`;
},
});
this.set("args", { id: 1234 });
await render(hbs`<MountWidget @widget="id-test" @args={{this.args}} />`);
assert.ok(exists("#test-1234"));
});
test("widget state", async function (assert) {
createWidget("state-test", {
tagName: "button.test",
buildKey: () => `button-test`,
template: widgetHbs`{{state.clicks}} clicks`,
defaultState() {
return { clicks: 0 };
},
click() {
this.state.clicks++;
},
});
await render(hbs`<MountWidget @widget="state-test" />`);
assert.ok(exists("button.test"), "it renders the button");
assert.strictEqual(query("button.test").innerText, "0 clicks");
await click(query("button"));
assert.strictEqual(query("button.test").innerText, "1 clicks");
});
test("widget update with promise", async function (assert) {
createWidget("promise-test", {
tagName: "button.test",
buildKey: () => "promise-test",
template: widgetHbs`
{{#if state.name}}
{{state.name}}
{{else}}
No name
{{/if}}
`,
click() {
return new Promise((resolve) => {
next(() => {
this.state.name = "Robin";
resolve();
});
});
},
});
await render(hbs`<MountWidget @widget="promise-test" />`);
assert.strictEqual(query("button.test").innerText.trim(), "No name");
await click(query("button"));
assert.strictEqual(query("button.test").innerText.trim(), "Robin");
});
test("widget attaching", async function (assert) {
createWidget("test-embedded", { tagName: "div.embedded" });
createWidget("attach-test", {
tagName: "div.container",
template: widgetHbs`{{attach widget="test-embedded" attrs=attrs}}`,
});
await render(hbs`<MountWidget @widget="attach-test" />`);
assert.ok(exists(".container"), "renders container");
assert.ok(exists(".container .embedded"), "renders attached");
});
test("magic attaching by name", async function (assert) {
createWidget("test-embedded", { tagName: "div.embedded" });
createWidget("attach-test", {
tagName: "div.container",
template: widgetHbs`{{test-embedded attrs=attrs}}`,
});
await render(hbs`<MountWidget @widget="attach-test" />`);
assert.ok(exists(".container"), "renders container");
assert.ok(exists(".container .embedded"), "renders attached");
});
test("custom attrs to a magic attached widget", async function (assert) {
createWidget("testing", {
tagName: "span.value",
template: widgetHbs`{{attrs.value}}`,
});
createWidget("attach-test", {
tagName: "div.container",
template: widgetHbs`{{testing value=(concat "hello" " " "world")}}`,
});
await render(hbs`<MountWidget @widget="attach-test" />`);
assert.ok(exists(".container"), "renders container");
assert.strictEqual(query(".container .value").innerText, "hello world");
});
test("using transformed values in a sub-expression", async function (assert) {
createWidget("testing", {
tagName: "span.value",
template: widgetHbs`{{attrs.value}}`,
});
createWidget("attach-test", {
transform() {
return { someValue: "world" };
},
tagName: "div.container",
template: widgetHbs`{{testing value=(concat "hello" " " transformed.someValue)}}`,
});
await render(hbs`<MountWidget @widget="attach-test" />`);
assert.ok(count(".container"), "renders container");
assert.strictEqual(query(".container .value").innerText, "hello world");
});
test("handlebars d-icon", async function (assert) {
createWidget("hbs-icon-test", {
template: widgetHbs`{{d-icon "arrow-down"}}`,
});
await render(
hbs`<MountWidget @widget="hbs-icon-test" @args={{this.args}} />`
);
assert.strictEqual(count(".d-icon-arrow-down"), 1);
});
test("handlebars i18n", async function (assert) {
createWidget("hbs-i18n-test", {
template: widgetHbs`
<span class='string'>{{i18n "hbs_test0"}}</span>
<span class='var'>{{i18n attrs.key}}</span>
<a href title={{i18n "hbs_test0"}}>test</a>
`,
});
I18n.translations = {
en: {
js: {
hbs_test0: "evil",
hbs_test1: "trout",
},
},
};
this.set("args", { key: "hbs_test1" });
await render(
hbs`<MountWidget @widget="hbs-i18n-test" @args={{this.args}} />`
);
// coming up
assert.strictEqual(query("span.string").innerText, "evil");
assert.strictEqual(query("span.var").innerText, "trout");
assert.strictEqual(query("a").title, "evil");
});
test("handlebars #each", async function (assert) {
createWidget("hbs-each-test", {
tagName: "ul",
template: widgetHbs`
{{#each attrs.items as |item|}}
<li>{{item}}</li>
{{/each}}
`,
});
this.set("args", {
items: ["one", "two", "three"],
});
await render(
hbs`<MountWidget @widget="hbs-each-test" @args={{this.args}} />`
);
assert.strictEqual(count("ul li"), 3);
assert.strictEqual(query("ul li:nth-of-type(1)").innerText, "one");
});
test("widget decorating", async function (assert) {
createWidget("decorate-test", {
tagName: "div.decorate",
template: widgetHbs`main content`,
});
withPluginApi("0.1", (api) => {
api.decorateWidget("decorate-test:before", (dec) => {
return dec.h("b", "before");
});
api.decorateWidget("decorate-test:after", (dec) => {
return dec.h("i", "after");
});
});
await render(hbs`<MountWidget @widget="decorate-test" />`);
assert.ok(exists(".decorate"));
assert.strictEqual(query(".decorate b").innerText, "before");
assert.strictEqual(query(".decorate i").innerText, "after");
});
test("widget settings", async function (assert) {
createWidget("settings-test", {
tagName: "div.settings",
template: widgetHbs`age is {{settings.age}}`,
settings: { age: 36 },
});
await render(hbs`<MountWidget @widget="settings-test" />`);
assert.strictEqual(query(".settings").innerText, "age is 36");
});
test("override settings", async function (assert) {
createWidget("ov-settings-test", {
tagName: "div.settings",
template: widgetHbs`age is {{settings.age}}`,
settings: { age: 36 },
});
withPluginApi("0.1", (api) => {
api.changeWidgetSetting("ov-settings-test", "age", 37);
});
await render(hbs`<MountWidget @widget="ov-settings-test" />`);
assert.strictEqual(query(".settings").innerText, "age is 37");
});
test("get accessor", async function (assert) {
createWidget("get-accessor-test", {
tagName: "div.test",
template: widgetHbs`Hello {{transformed.name}}`,
transform() {
return {
name: this.get("currentUser.username"),
};
},
});
await render(hbs`<MountWidget @widget="get-accessor-test" />`);
assert.strictEqual(query("div.test").innerText, "Hello eviltrout");
});
test("tagName", async function (assert) {
createWidget("test-override", { tagName: "div.not-override" });
createWidget("tag-name-override-test", {
template: widgetHbs`{{attach widget="test-override" attrs=attrs otherOpts=(hash tagName="section.override")}}`,
});
await render(hbs`<MountWidget @widget="tag-name-override-test" />`);
assert.ok(
exists("section.override"),
"renders container with overridden tagName"
);
});
});

View File

@ -1,100 +1,73 @@
import { import { module, test } from "qunit";
count, import { setupRenderingTest } from "discourse/tests/helpers/component-test";
discourseModule, import { click, fillIn, render } from "@ember/test-helpers";
exists, import { count, exists } from "discourse/tests/helpers/qunit-helpers";
} from "discourse/tests/helpers/qunit-helpers";
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { click, fillIn } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
discourseModule( module("Integration | Component | Wizard | invite-list", function (hooks) {
"Integration | Component | Wizard | invite-list", setupRenderingTest(hooks);
function (hooks) {
setupRenderingTest(hooks);
componentTest("can add users", { test("can add users", async function (assert) {
template: hbs`{{invite-list field=field}}`, this.set("field", {});
beforeEach() { await render(hbs`<InviteList @field={{this.field}} />`);
this.set("field", {});
},
async test(assert) { assert.ok(!exists(".users-list .invite-list-user"), "no users at first");
assert.ok( assert.ok(!exists(".new-user .invalid"), "not invalid at first");
!exists(".users-list .invite-list-user"),
"no users at first"
);
assert.ok(!exists(".new-user .invalid"), "not invalid at first");
const firstVal = JSON.parse(this.field.value); const firstVal = JSON.parse(this.field.value);
assert.strictEqual(firstVal.length, 0, "empty JSON at first"); assert.strictEqual(firstVal.length, 0, "empty JSON at first");
assert.ok( assert.ok(this.field.warning, "it has a warning since no users were added");
this.field.warning,
"it has a warning since no users were added"
);
await click(".add-user"); await click(".add-user");
assert.ok( assert.ok(
!exists(".users-list .invite-list-user"), !exists(".users-list .invite-list-user"),
"doesn't add a blank user" "doesn't add a blank user"
); );
assert.strictEqual(count(".new-user .invalid"), 1); assert.strictEqual(count(".new-user .invalid"), 1);
await fillIn(".invite-email", "eviltrout@example.com"); await fillIn(".invite-email", "eviltrout@example.com");
await click(".add-user"); await click(".add-user");
assert.strictEqual( assert.strictEqual(
count(".users-list .invite-list-user"), count(".users-list .invite-list-user"),
1, 1,
"adds the user" "adds the user"
); );
assert.ok(!exists(".new-user .invalid")); assert.ok(!exists(".new-user .invalid"));
const val = JSON.parse(this.field.value); const val = JSON.parse(this.field.value);
assert.strictEqual(val.length, 1); assert.strictEqual(val.length, 1);
assert.strictEqual( assert.strictEqual(
val[0].email, val[0].email,
"eviltrout@example.com", "eviltrout@example.com",
"adds the email to the JSON" "adds the email to the JSON"
); );
assert.ok(val[0].role.length, "adds the role to the JSON"); assert.ok(val[0].role.length, "adds the role to the JSON");
assert.ok( assert.ok(!this.get("field.warning"), "no warning once the user is added");
!this.get("field.warning"),
"no warning once the user is added"
);
await fillIn(".invite-email", "eviltrout@example.com"); await fillIn(".invite-email", "eviltrout@example.com");
await click(".add-user"); await click(".add-user");
assert.strictEqual( assert.strictEqual(
count(".users-list .invite-list-user"), count(".users-list .invite-list-user"),
1, 1,
"can't add the same user twice" "can't add the same user twice"
); );
assert.strictEqual(count(".new-user .invalid"), 1); assert.strictEqual(count(".new-user .invalid"), 1);
await fillIn(".invite-email", "not-an-email"); await fillIn(".invite-email", "not-an-email");
await click(".add-user"); await click(".add-user");
assert.strictEqual( assert.strictEqual(
count(".users-list .invite-list-user"), count(".users-list .invite-list-user"),
1, 1,
"won't add an invalid email" "won't add an invalid email"
); );
assert.strictEqual(count(".new-user .invalid"), 1); assert.strictEqual(count(".new-user .invalid"), 1);
await click( await click(".invite-list .invite-list-user:nth-of-type(1) .remove-user");
".invite-list .invite-list-user:nth-of-type(1) .remove-user" assert.ok(!exists(".users-list .invite-list-user"), 0, "removed the user");
); });
assert.ok( });
!exists(".users-list .invite-list-user"),
0,
"removed the user"
);
},
});
}
);

View File

@ -1,35 +0,0 @@
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { count, discourseModule } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
discourseModule(
"Integration | Component | Widget | actions-summary",
function (hooks) {
setupRenderingTest(hooks);
componentTest("post deleted", {
template: hbs`{{mount-widget widget="actions-summary" args=args}}`,
beforeEach() {
this.set("args", {
deleted_at: "2016-01-01",
deletedByUsername: "eviltrout",
deletedByAvatarTemplate: "/images/avatar.png",
});
},
test(assert) {
assert.strictEqual(
count(".post-action .d-icon-far-trash-alt"),
1,
"it has the deleted icon"
);
assert.strictEqual(
count(".avatar[title=eviltrout]"),
1,
"it has the deleted by avatar"
);
},
});
}
);

View File

@ -1,49 +0,0 @@
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import {
discourseModule,
exists,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
discourseModule(
"Integration | Component | Widget | avatar-flair",
function (hooks) {
setupRenderingTest(hooks);
componentTest("avatar flair with an icon", {
template: hbs`{{mount-widget widget="avatar-flair" args=args}}`,
beforeEach() {
this.set("args", {
flair_url: "fa-bars",
flair_bg_color: "CC0000",
flair_color: "FFFFFF",
});
},
test(assert) {
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(exists("svg.d-icon-bars"), "it has the svg icon");
assert.strictEqual(
queryAll(".avatar-flair").attr("style"),
"background-color: #CC0000; color: #FFFFFF; ",
"it has styles"
);
},
});
componentTest("avatar flair with an image", {
template: hbs`{{mount-widget widget="avatar-flair" args=args}}`,
beforeEach() {
this.set("args", {
flair_url: "/images/avatar.png",
});
},
test(assert) {
assert.ok(exists(".avatar-flair"), "it has the tag");
assert.ok(!exists("svg"), "it does not have an svg icon");
},
});
}
);

View File

@ -1,97 +0,0 @@
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import {
discourseModule,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
discourseModule("Integration | Component | Widget | button", function (hooks) {
setupRenderingTest(hooks);
componentTest("icon only button", {
template: hbs`{{mount-widget widget="button" args=args}}`,
beforeEach() {
this.set("args", { icon: "far-smile" });
},
test(assert) {
assert.ok(
exists("button.btn.btn-icon.no-text"),
"it has all the classes"
);
assert.ok(exists("button .d-icon.d-icon-far-smile"), "it has the icon");
},
});
componentTest("icon and text button", {
template: hbs`{{mount-widget widget="button" args=args}}`,
beforeEach() {
this.set("args", { icon: "plus", label: "topic.create" });
},
test(assert) {
assert.ok(exists("button.btn.btn-icon-text"), "it has all the classes");
assert.ok(exists("button .d-icon.d-icon-plus"), "it has the icon");
assert.ok(exists("button span.d-button-label"), "it has the label");
},
});
componentTest("emoji and text button", {
template: hbs`{{mount-widget widget="button" args=args}}`,
beforeEach() {
this.set("args", { emoji: "mega", label: "topic.create" });
},
test(assert) {
assert.ok(exists("button.widget-button"), "renders the widget");
assert.ok(exists("button img.emoji"), "it renders the emoji");
assert.ok(exists("button span.d-button-label"), "it renders the label");
},
});
componentTest("text only button", {
template: hbs`{{mount-widget widget="button" args=args}}`,
beforeEach() {
this.set("args", { label: "topic.create" });
},
test(assert) {
assert.ok(exists("button.btn.btn-text"), "it has all the classes");
assert.ok(exists("button span.d-button-label"), "it has the label");
},
});
componentTest("translatedLabel", {
template: hbs`{{mount-widget widget="button" args=args}}`,
beforeEach() {
this.set("args", { translatedLabel: "foo bar" });
},
test(assert) {
assert.strictEqual(
query("button span.d-button-label").innerText,
"foo bar"
);
},
});
componentTest("translatedTitle", {
template: hbs`{{mount-widget widget="button" args=args}}`,
beforeEach() {
this.set("args", { label: "topic.create", translatedTitle: "foo bar" });
},
test(assert) {
assert.strictEqual(query("button").title, "foo bar");
},
});
});

Some files were not shown because too many files have changed in this diff Show More