DEV: select-kit 2 (#7998)
This new iteration of select-kit focuses on following best principales and disallowing mutations inside select-kit components. A best effort has been made to avoid breaking changes, however if you content was a flat array, eg: ["foo", "bar"] You will need to set valueProperty=null and nameProperty=null on the component. Also almost every component should have an `onChange` handler now to decide what to do with the updated data. **select-kit will not mutate your data by itself anymore**
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule } from "./select-kit-test-helper";
|
||||
|
||||
testSelectKitModule("category-chooser");
|
||||
|
||||
function template(options = []) {
|
||||
return `
|
||||
{{category-chooser
|
||||
value=value
|
||||
options=(hash
|
||||
${options.join("\n")}
|
||||
)
|
||||
}}
|
||||
`;
|
||||
}
|
||||
|
||||
componentTest("with value", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
this.set("value", 2);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.equal(this.subject.header().value(), 2);
|
||||
assert.equal(this.subject.header().label(), "feature");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with excludeCategoryId", {
|
||||
template: template(["excludeCategoryId=2"]),
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.notOk(this.subject.rowByValue(2).exists());
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with scopedCategoryId", {
|
||||
template: template(["scopedCategoryId=2"]),
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.equal(
|
||||
this.subject.rowByIndex(0).title(),
|
||||
"Discussion about features or potential features of Discourse: how they work, why they work, etc."
|
||||
);
|
||||
assert.equal(this.subject.rowByIndex(0).value(), 2);
|
||||
assert.equal(
|
||||
this.subject.rowByIndex(1).title(),
|
||||
"My idea here is to have mini specs for features we would like built but have no bandwidth to build"
|
||||
);
|
||||
assert.equal(this.subject.rowByIndex(1).value(), 26);
|
||||
assert.equal(this.subject.rows().length, 2);
|
||||
|
||||
await this.subject.fillInFilter("spec");
|
||||
|
||||
assert.equal(this.subject.rows().length, 1);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with allowUncategorized=null", {
|
||||
template: template(["allowUncategorized=null"]),
|
||||
|
||||
beforeEach() {
|
||||
this.siteSettings.allow_uncategorized_topics = false;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.subject.header().value(), null);
|
||||
assert.equal(this.subject.header().label(), "category…");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with allowUncategorized=null rootNone=true", {
|
||||
template: template(["allowUncategorized=null", "none=true"]),
|
||||
|
||||
beforeEach() {
|
||||
this.siteSettings.allow_uncategorized_topics = false;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.subject.header().value(), null);
|
||||
assert.equal(this.subject.header().label(), "(no category)");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with disallowed uncategorized, none", {
|
||||
template: template(["allowUncategorized=null", "none='test.root'"]),
|
||||
|
||||
beforeEach() {
|
||||
I18n.translations[I18n.locale].js.test = { root: "root none label" };
|
||||
this.siteSettings.allow_uncategorized_topics = false;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.subject.header().value(), null);
|
||||
assert.equal(this.subject.header().label(), "root none label");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with allowed uncategorized", {
|
||||
template: template(["allowUncategorized=true"]),
|
||||
|
||||
beforeEach() {
|
||||
this.siteSettings.allow_uncategorized_topics = true;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.subject.header().value(), null);
|
||||
assert.equal(this.subject.header().label(), "uncategorized");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with allowed uncategorized and none=true", {
|
||||
template: template(["allowUncategorized=true", "none=true"]),
|
||||
|
||||
beforeEach() {
|
||||
this.siteSettings.allow_uncategorized_topics = true;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.subject.header().value(), null);
|
||||
assert.equal(this.subject.header().label(), "(no category)");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("with allowed uncategorized and none", {
|
||||
template: template(["allowUncategorized=true", "none='test.root'"]),
|
||||
|
||||
beforeEach() {
|
||||
I18n.translations[I18n.locale].js.test = { root: "root none label" };
|
||||
this.siteSettings.allow_uncategorized_topics = true;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.subject.header().value(), null);
|
||||
assert.equal(this.subject.header().label(), "root none label");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,336 @@
|
||||
import Category from "discourse/models/category";
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule } from "./select-kit-test-helper";
|
||||
import {
|
||||
NO_CATEGORIES_ID,
|
||||
ALL_CATEGORIES_ID
|
||||
} from "select-kit/components/category-drop";
|
||||
|
||||
testSelectKitModule("category-drop");
|
||||
|
||||
function initCategories(context) {
|
||||
const categories = context.site.categoriesList;
|
||||
context.setProperties({
|
||||
category: categories.firstObject,
|
||||
categories
|
||||
});
|
||||
}
|
||||
|
||||
function initCategoriesWithParentCategory(context) {
|
||||
const parentCategory = Category.findById(2);
|
||||
const childCategories = context.site.categoriesList.filter(c => {
|
||||
return c.parentCategory === parentCategory;
|
||||
});
|
||||
|
||||
context.setProperties({
|
||||
parentCategory,
|
||||
category: null,
|
||||
categories: childCategories
|
||||
});
|
||||
}
|
||||
|
||||
function template(options = []) {
|
||||
return `
|
||||
{{category-drop
|
||||
category=category
|
||||
categories=categories
|
||||
parentCategory=parentCategory
|
||||
options=(hash
|
||||
${options.join("\n")}
|
||||
)
|
||||
}}
|
||||
`;
|
||||
}
|
||||
|
||||
componentTest("caretUpIcon", {
|
||||
template: `
|
||||
{{category-drop
|
||||
category=value
|
||||
categories=content
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
const $header = this.subject.header().el();
|
||||
|
||||
assert.ok(
|
||||
exists($header.find(`.d-icon-caret-right`)),
|
||||
"it uses the correct default icon"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("none", {
|
||||
template: `
|
||||
{{category-drop
|
||||
category=value
|
||||
categories=content
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
const text = this.subject.header().label();
|
||||
assert.equal(
|
||||
text,
|
||||
I18n.t("category.all").toLowerCase(),
|
||||
"it uses the noneLabel"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("[not staff - TL0] displayCategoryDescription", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
Ember.set(this.currentUser, "staff", false);
|
||||
Ember.set(this.currentUser, "trustLevel", 0);
|
||||
|
||||
initCategories(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const row = this.subject.rowByValue(this.category.id);
|
||||
assert.ok(
|
||||
exists(row.el().find(".category-desc")),
|
||||
"it shows category description for newcomers"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("[not staff - TL1] displayCategoryDescription", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
Ember.set(this.currentUser, "staff", false);
|
||||
Ember.set(this.currentUser, "trustLevel", 1);
|
||||
|
||||
initCategories(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const row = this.subject.rowByValue(this.category.id);
|
||||
assert.ok(
|
||||
exists(row.el().find(".category-desc")),
|
||||
"it doesn't show category description for TL0+"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("[staff - TL0] displayCategoryDescription", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
Ember.set(this.currentUser, "staff", true);
|
||||
Ember.set(this.currentUser, "trustLevel", 0);
|
||||
|
||||
initCategories(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const row = this.subject.rowByValue(this.category.id);
|
||||
assert.ok(
|
||||
exists(row.el().find(".category-desc")),
|
||||
"it doesn't show category description for staff"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("hideParentCategory (default: false)", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
initCategories(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const row = this.subject.rowByValue(this.category.id);
|
||||
assert.equal(row.value(), this.category.id);
|
||||
assert.equal(this.category.parent_category_id, null);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("hideParentCategory (true)", {
|
||||
template: template(["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().find(".category-status");
|
||||
assert.ok(
|
||||
$categoryStatus
|
||||
.text()
|
||||
.trim()
|
||||
.match(/^spec/)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("allowUncategorized (default: true)", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
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("allowUncategorized (false)", {
|
||||
template: template(["allowUncategorized=false"]),
|
||||
|
||||
beforeEach() {
|
||||
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: template(),
|
||||
|
||||
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()
|
||||
.find(".topic-count")
|
||||
.text()
|
||||
.trim();
|
||||
|
||||
assert.equal(
|
||||
topicCount,
|
||||
"× 481",
|
||||
"it doesn't include the topic count of subcategories"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("countSubcategories (true)", {
|
||||
template: template(["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()
|
||||
.find(".topic-count")
|
||||
.text()
|
||||
.trim();
|
||||
|
||||
assert.equal(
|
||||
topicCount,
|
||||
"× 584",
|
||||
"it includes the topic count of subcategories"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("shortcuts:default", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
initCategories(this);
|
||||
this.set("category", null);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.equal(
|
||||
this.subject.rowByIndex(0).value(),
|
||||
this.categories.firstObject.id,
|
||||
"Shortcuts are not prepended when no category is selected"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("shortcuts:category is set", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
initCategories(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.equal(this.subject.rowByIndex(0).value(), ALL_CATEGORIES_ID);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("shortcuts with parentCategory/subCategory=true:default", {
|
||||
template: template(["subCategory=true"]),
|
||||
|
||||
beforeEach() {
|
||||
initCategoriesWithParentCategory(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.equal(this.subject.rowByIndex(0).value(), NO_CATEGORIES_ID);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest(
|
||||
"shortcuts with parentCategory/subCategory=true:category is selected",
|
||||
{
|
||||
template: template(["subCategory=true"]),
|
||||
|
||||
beforeEach() {
|
||||
initCategoriesWithParentCategory(this);
|
||||
this.set("category", this.categories.firstObject);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.equal(this.subject.rowByIndex(0).value(), ALL_CATEGORIES_ID);
|
||||
assert.equal(this.subject.rowByIndex(1).value(), NO_CATEGORIES_ID);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,102 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import componentTest from "helpers/component-test";
|
||||
|
||||
moduleForComponent("select-kit/combo-box", {
|
||||
integration: true,
|
||||
beforeEach() {
|
||||
this.set("subject", selectKit());
|
||||
}
|
||||
});
|
||||
|
||||
const DEFAULT_CONTENT = [
|
||||
{ id: 1, name: "foo" },
|
||||
{ id: 2, name: "bar" },
|
||||
{ id: 3, name: "baz" }
|
||||
];
|
||||
|
||||
const DEFAULT_VALUE = 1;
|
||||
|
||||
const setDefaultState = (ctx, options) => {
|
||||
const properties = Object.assign(
|
||||
{
|
||||
content: DEFAULT_CONTENT,
|
||||
value: DEFAULT_VALUE
|
||||
},
|
||||
options || {}
|
||||
);
|
||||
ctx.setProperties(properties);
|
||||
};
|
||||
|
||||
componentTest("options.clearable", {
|
||||
template: `
|
||||
{{combo-box
|
||||
value=value
|
||||
content=content
|
||||
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(
|
||||
exists($header.el().find(".btn-clear")),
|
||||
"it shows the clear button"
|
||||
);
|
||||
assert.equal($header.value(), DEFAULT_VALUE);
|
||||
|
||||
await click($header.el().find(".btn-clear"));
|
||||
|
||||
assert.notOk(
|
||||
exists($header.el().find(".btn-clear")),
|
||||
"it hides the clear button"
|
||||
);
|
||||
assert.equal($header.value(), null);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("options.{caretUpIcon,caretDownIcon}", {
|
||||
template: `
|
||||
{{combo-box
|
||||
value=value
|
||||
content=content
|
||||
options=(hash
|
||||
caretUpIcon=caretUpIcon
|
||||
caretDownIcon=caretDownIcon
|
||||
)
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this, {
|
||||
caretUpIcon: "pencil-alt",
|
||||
caretDownIcon: "trash-alt"
|
||||
});
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
const $header = this.subject.header().el();
|
||||
|
||||
assert.ok(
|
||||
exists($header.find(`.d-icon-${this.caretDownIcon}`)),
|
||||
"it uses the icon provided"
|
||||
);
|
||||
|
||||
await this.subject.expand();
|
||||
|
||||
assert.ok(
|
||||
exists($header.find(`.d-icon-${this.caretUpIcon}`)),
|
||||
"it uses the icon provided"
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,111 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import componentTest from "helpers/component-test";
|
||||
|
||||
moduleForComponent("select-kit/dropdown-select-box", {
|
||||
integration: true,
|
||||
beforeEach() {
|
||||
this.set("subject", selectKit());
|
||||
}
|
||||
});
|
||||
|
||||
const DEFAULT_CONTENT = [
|
||||
{ id: 1, name: "foo" },
|
||||
{ id: 2, name: "bar" },
|
||||
{ id: 3, name: "baz" }
|
||||
];
|
||||
|
||||
const DEFAULT_VALUE = 1;
|
||||
|
||||
const setDefaultState = (ctx, options) => {
|
||||
const properties = Object.assign(
|
||||
{
|
||||
content: DEFAULT_CONTENT,
|
||||
value: DEFAULT_VALUE,
|
||||
onChange: value => {
|
||||
this.set("value", value);
|
||||
}
|
||||
},
|
||||
options || {}
|
||||
);
|
||||
ctx.setProperties(properties);
|
||||
};
|
||||
|
||||
componentTest("selection behavior", {
|
||||
template: `
|
||||
{{dropdown-select-box
|
||||
value=value
|
||||
content=content
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
assert.ok(this.subject.isExpanded());
|
||||
|
||||
await this.subject.selectRowByValue(DEFAULT_VALUE);
|
||||
assert.notOk(
|
||||
this.subject.isExpanded(),
|
||||
"it collapses the dropdown on select"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("options.showFullTitle=false", {
|
||||
template: `
|
||||
{{dropdown-select-box
|
||||
value=value
|
||||
content=content
|
||||
options=(hash
|
||||
showFullTitle=showFullTitle
|
||||
)
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this, { showFullTitle: false });
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(
|
||||
!exists(
|
||||
this.subject
|
||||
.header()
|
||||
.el()
|
||||
.find(".selected-name .body")
|
||||
),
|
||||
"it hides the text of the selected item"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("options.showFullTitle=true", {
|
||||
template: `
|
||||
{{dropdown-select-box
|
||||
value=value
|
||||
content=content
|
||||
options=(hash
|
||||
showFullTitle=showFullTitle
|
||||
)
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this, { showFullTitle: true });
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(
|
||||
exists(
|
||||
this.subject
|
||||
.header()
|
||||
.el()
|
||||
.find(".selected-name")
|
||||
),
|
||||
"it shows the text of the selected item"
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule } from "./select-kit-test-helper";
|
||||
|
||||
testSelectKitModule("list-setting");
|
||||
|
||||
function template(options = []) {
|
||||
return `
|
||||
{{list-setting
|
||||
value=value
|
||||
choices=choices
|
||||
options=(hash
|
||||
${options.join("\n")}
|
||||
)
|
||||
}}
|
||||
`;
|
||||
}
|
||||
|
||||
componentTest("default", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
this.set("value", ["bold", "italic"]);
|
||||
this.set("choices", ["bold", "italic", "underline"]);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.equal(this.subject.header().name(), "bold,italic");
|
||||
assert.equal(this.subject.header().value(), "bold,italic");
|
||||
|
||||
await this.subject.expand();
|
||||
|
||||
assert.equal(this.subject.rows().length, 1);
|
||||
assert.equal(this.subject.rowByIndex(0).value(), "underline");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule } from "./select-kit-test-helper";
|
||||
|
||||
testSelectKitModule("multi-select");
|
||||
|
||||
function template(options = []) {
|
||||
return `
|
||||
{{multi-select
|
||||
value=value
|
||||
content=content
|
||||
options=(hash
|
||||
${options.join("\n")}
|
||||
)
|
||||
}}
|
||||
`;
|
||||
}
|
||||
|
||||
const DEFAULT_CONTENT = [
|
||||
{ id: 1, name: "foo" },
|
||||
{ id: 2, name: "bar" },
|
||||
{ id: 3, name: "baz" }
|
||||
];
|
||||
|
||||
const setDefaultState = (ctx, options) => {
|
||||
const properties = Object.assign(
|
||||
{
|
||||
content: DEFAULT_CONTENT,
|
||||
value: null
|
||||
},
|
||||
options || {}
|
||||
);
|
||||
ctx.setProperties(properties);
|
||||
};
|
||||
|
||||
componentTest("content", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const content = this.subject.displayedContent();
|
||||
assert.equal(content.length, 3, "it shows rows");
|
||||
assert.equal(
|
||||
content[0].name,
|
||||
this.content.firstObject.name,
|
||||
"it has the correct name"
|
||||
);
|
||||
assert.equal(
|
||||
content[0].id,
|
||||
this.content.firstObject.id,
|
||||
"it has the correct value"
|
||||
);
|
||||
assert.equal(
|
||||
this.subject.header().value(),
|
||||
null,
|
||||
"it doesn't set a value from the content"
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule, setDefaultState } from "./select-kit-test-helper";
|
||||
|
||||
testSelectKitModule("notifications-button");
|
||||
|
||||
componentTest("default", {
|
||||
template: `
|
||||
{{notifications-button
|
||||
value=value
|
||||
options=(hash
|
||||
i18nPrefix=i18nPrefix
|
||||
i18nPostfix=i18nPostfix
|
||||
)
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("value", 1);
|
||||
|
||||
setDefaultState(this, 1, { i18nPrefix: "pre", i18nPostfix: "post" });
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(this.subject.header().value());
|
||||
|
||||
assert.ok(
|
||||
this.subject
|
||||
.header()
|
||||
.label()
|
||||
.includes(`${this.i18nPrefix}.regular${this.i18nPostfix}`),
|
||||
"it shows the regular choice when value is not set"
|
||||
);
|
||||
|
||||
const icon = this.subject.header().icon()[0];
|
||||
assert.ok(
|
||||
icon.classList.contains("d-icon-d-regular"),
|
||||
"it shows the correct icon"
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import componentTest from "helpers/component-test";
|
||||
import Topic from "discourse/models/topic";
|
||||
|
||||
const buildTopic = function() {
|
||||
return Topic.create({
|
||||
id: 1234,
|
||||
title: "Qunit Test Topic",
|
||||
deleted: false,
|
||||
pinned: true
|
||||
});
|
||||
};
|
||||
|
||||
moduleForComponent("select-kit/pinned-options", {
|
||||
integration: true,
|
||||
beforeEach: function() {
|
||||
this.set("subject", selectKit());
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("updating the content refreshes the list", {
|
||||
template: "{{pinned-options value=pinned topic=topic}}",
|
||||
|
||||
beforeEach() {
|
||||
this.siteSettings.automatically_unpin_topics = false;
|
||||
this.set("topic", buildTopic());
|
||||
this.set("pinned", "pinned");
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.equal(this.subject.header().name(), "pinned");
|
||||
|
||||
// we do it manually as clearPin is an ajax call
|
||||
await this.set("pinned", false);
|
||||
|
||||
assert.equal(this.subject.header().name(), "unpinned");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
|
||||
export function testSelectKitModule(moduleName, options = {}) {
|
||||
moduleForComponent(`select-kit/${moduleName}`, {
|
||||
integration: true,
|
||||
beforeEach() {
|
||||
this.set("subject", selectKit());
|
||||
options.beforeEach && options.beforeEach.call(this);
|
||||
},
|
||||
afterEach() {
|
||||
options.afterEach && options.afterEach.call(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const DEFAULT_CONTENT = [
|
||||
{ id: 1, name: "foo" },
|
||||
{ id: 2, name: "bar" },
|
||||
{ id: 3, name: "baz" }
|
||||
];
|
||||
|
||||
export function setDefaultState(ctx, value, options = {}) {
|
||||
const properties = Object.assign(
|
||||
{
|
||||
onChange: v => {
|
||||
this.set("value", v);
|
||||
}
|
||||
},
|
||||
options || {}
|
||||
);
|
||||
|
||||
ctx.setProperties(properties);
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule } from "./select-kit-test-helper";
|
||||
|
||||
testSelectKitModule("single-select");
|
||||
|
||||
function template(options = []) {
|
||||
return `
|
||||
{{single-select
|
||||
value=value
|
||||
content=content
|
||||
nameProperty=nameProperty
|
||||
valueProperty=valueProperty
|
||||
onChange=onChange
|
||||
options=(hash
|
||||
${options.join("\n")}
|
||||
)
|
||||
}}
|
||||
`;
|
||||
}
|
||||
|
||||
const DEFAULT_CONTENT = [
|
||||
{ id: 1, name: "foo" },
|
||||
{ id: 2, name: "bar" },
|
||||
{ id: 3, name: "baz" }
|
||||
];
|
||||
|
||||
const DEFAULT_VALUE = 1;
|
||||
|
||||
const setDefaultState = (ctx, options) => {
|
||||
const properties = Object.assign(
|
||||
{
|
||||
content: DEFAULT_CONTENT,
|
||||
value: DEFAULT_VALUE,
|
||||
nameProperty: "name",
|
||||
valueProperty: "id",
|
||||
onChange: value => {
|
||||
ctx.set("value", value);
|
||||
}
|
||||
},
|
||||
options || {}
|
||||
);
|
||||
ctx.setProperties(properties);
|
||||
};
|
||||
|
||||
componentTest("content", {
|
||||
template: "{{single-select content=content}}",
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const content = this.subject.displayedContent();
|
||||
assert.equal(content.length, 3, "it shows rows");
|
||||
assert.equal(
|
||||
content[0].name,
|
||||
this.content.firstObject.name,
|
||||
"it has the correct name"
|
||||
);
|
||||
assert.equal(
|
||||
content[0].id,
|
||||
this.content.firstObject.id,
|
||||
"it has the correct value"
|
||||
);
|
||||
assert.equal(
|
||||
this.subject.header().value(),
|
||||
null,
|
||||
"it doesn't set a value from the content"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("value", {
|
||||
template: template(),
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
this.subject.header().value(this.content),
|
||||
1,
|
||||
"it selects the correct content to display"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("options.filterable", {
|
||||
template: template(["filterable=filterable"]),
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this, { filterable: true });
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
assert.ok(this.subject.filter().exists(), "it shows the filter");
|
||||
|
||||
const filter = this.subject.displayedContent()[1].name;
|
||||
await this.subject.fillInFilter(filter);
|
||||
assert.equal(
|
||||
this.subject.displayedContent()[0].name,
|
||||
filter,
|
||||
"it filters the list"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("options.limitMatches", {
|
||||
template: template(["limitMatches=limitMatches", "filterable=filterable"]),
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this, { limitMatches: 1, filterable: true });
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
await this.subject.fillInFilter("ba");
|
||||
|
||||
assert.equal(
|
||||
this.subject.displayedContent().length,
|
||||
1,
|
||||
"it returns only 1 result"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("valueAttribute (deprecated)", {
|
||||
template: `
|
||||
{{single-select
|
||||
value=value
|
||||
content=content
|
||||
valueAttribute="value"
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("value", "normal");
|
||||
|
||||
const content = [
|
||||
{ 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.equal(this.subject.selectedRow().value(), this.value);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("none:string", {
|
||||
template: template(['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.equal(noneRow.value(), null);
|
||||
assert.equal(noneRow.name(), I18n.t("test.none"));
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("none:object", {
|
||||
template: template(["none=none"]),
|
||||
|
||||
beforeEach() {
|
||||
setDefaultState(this, { none: { value: null, name: "(default)" } });
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
const noneRow = this.subject.rowByIndex(0);
|
||||
assert.equal(noneRow.value(), null);
|
||||
assert.equal(noneRow.name(), "(default)");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("content is a basic array", {
|
||||
template: template(['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.equal(noneRow.value(), I18n.t("test.none"));
|
||||
assert.equal(noneRow.name(), I18n.t("test.none"));
|
||||
assert.equal(this.value, "foo");
|
||||
|
||||
await this.subject.selectRowByIndex(0);
|
||||
|
||||
assert.equal(this.value, null);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
import componentTest from "helpers/component-test";
|
||||
import { testSelectKitModule } from "./select-kit-test-helper";
|
||||
import Site from "discourse/models/site";
|
||||
|
||||
testSelectKitModule("tag-drop", {
|
||||
beforeEach() {
|
||||
const site = Site.current();
|
||||
Ember.set(site, "top_tags", ["jeff", "neil", "arpit", "régis"]);
|
||||
|
||||
const response = object => {
|
||||
return [200, { "Content-Type": "application/json" }, object];
|
||||
};
|
||||
|
||||
// prettier-ignore
|
||||
server.get("/tags/filter/search", (params) => { //eslint-disable-line
|
||||
if (params.queryParams.q === "rég") {
|
||||
return response({
|
||||
"results": [
|
||||
{ "id": "régis", "text": "régis", "count": 2, "pm_count": 0 }
|
||||
]
|
||||
});
|
||||
}else if (params.queryParams.q === "dav") {
|
||||
return response({
|
||||
"results": [
|
||||
{ "id": "David", "text": "David", "count": 2, "pm_count": 0 }
|
||||
]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function initTags(context) {
|
||||
const categories = context.site.categoriesList;
|
||||
const parentCategory = categories.findBy("id", 2);
|
||||
const childCategories = categories.filter(
|
||||
c => c.parentCategory === parentCategory
|
||||
);
|
||||
|
||||
// top_tags
|
||||
context.setProperties({
|
||||
firstCategory: parentCategory,
|
||||
secondCategory: childCategories.firstObject,
|
||||
tagId: "jeff"
|
||||
});
|
||||
}
|
||||
|
||||
function template(options = []) {
|
||||
return `
|
||||
{{tag-drop
|
||||
firstCategory=firstCategory
|
||||
secondCategory=secondCategory
|
||||
tagId=tagId
|
||||
options=(hash
|
||||
${options.join("\n")}
|
||||
)
|
||||
}}
|
||||
`;
|
||||
}
|
||||
|
||||
componentTest("default", {
|
||||
template: template(["tagId=tagId"]),
|
||||
|
||||
beforeEach() {
|
||||
initTags(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
|
||||
assert.ok(true);
|
||||
// const row = this.subject.rowByValue(this.category.id);
|
||||
// assert.ok(
|
||||
// exists(row.el().find(".category-desc")),
|
||||
// "it shows category description for newcomers"
|
||||
// );
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import componentTest from "helpers/component-test";
|
||||
import Topic from "discourse/models/topic";
|
||||
|
||||
const buildTopic = function(level, archetype = "regular") {
|
||||
return Topic.create({
|
||||
id: 4563,
|
||||
title: "Qunit Test Topic",
|
||||
details: {
|
||||
notification_level: level
|
||||
},
|
||||
archetype
|
||||
});
|
||||
};
|
||||
|
||||
const originalTranslation =
|
||||
I18n.translations.en.js.topic.notifications.tracking_pm.title;
|
||||
|
||||
moduleForComponent("select-kit/topic-notifications-button", {
|
||||
integration: true,
|
||||
|
||||
afterEach() {
|
||||
I18n.translations.en.js.topic.notifications.tracking_pm.title = originalTranslation;
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("the header has a localized title", {
|
||||
template:
|
||||
"{{topic-notifications-button notificationLevel=topic.details.notification_level topic=topic}}",
|
||||
|
||||
beforeEach() {
|
||||
this.set("topic", buildTopic(1));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.equal(
|
||||
selectKit()
|
||||
.header()
|
||||
.label(),
|
||||
"Normal",
|
||||
"it has the correct label"
|
||||
);
|
||||
|
||||
await this.set("topic", buildTopic(2));
|
||||
|
||||
assert.equal(
|
||||
selectKit()
|
||||
.header()
|
||||
.label(),
|
||||
"Tracking",
|
||||
"it correctly changes the label"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("the header has a localized title", {
|
||||
template:
|
||||
"{{topic-notifications-button notificationLevel=topic.details.notification_level topic=topic}}",
|
||||
|
||||
beforeEach() {
|
||||
I18n.translations.en.js.topic.notifications.tracking_pm.title = `${originalTranslation} PM`;
|
||||
this.set("topic", buildTopic(2, "private_message"));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
selectKit()
|
||||
.header()
|
||||
.label(),
|
||||
`${originalTranslation} PM`,
|
||||
"it has the correct label for PMs"
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import componentTest from "helpers/component-test";
|
||||
import Topic from "discourse/models/topic";
|
||||
|
||||
const buildTopic = function(archetype) {
|
||||
return Topic.create({
|
||||
id: 4563,
|
||||
title: "Qunit Test Topic",
|
||||
details: {
|
||||
notification_level: 1
|
||||
},
|
||||
archetype
|
||||
});
|
||||
};
|
||||
|
||||
function extractDescs(rows) {
|
||||
return Array.from(
|
||||
rows.find(".desc").map(function() {
|
||||
return this.textContent.trim();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function getTranslations(type = "") {
|
||||
return ["watching", "tracking", "regular", "muted"].map(key => {
|
||||
return I18n.t(`topic.notifications.${key}${type}.description`);
|
||||
});
|
||||
}
|
||||
|
||||
moduleForComponent("select-kit/topic-notifications-options", {
|
||||
integration: true
|
||||
});
|
||||
|
||||
componentTest("regular topic notification level descriptions", {
|
||||
template:
|
||||
"{{topic-notifications-options value=topic.details.notification_level topic=topic}}",
|
||||
|
||||
beforeEach() {
|
||||
this.set("topic", buildTopic("regular"));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await selectKit().expand();
|
||||
|
||||
const uiTexts = extractDescs(selectKit().rows());
|
||||
const descriptions = getTranslations();
|
||||
|
||||
assert.equal(
|
||||
uiTexts.length,
|
||||
descriptions.length,
|
||||
"it has the correct copy"
|
||||
);
|
||||
uiTexts.forEach((text, index) => {
|
||||
assert.equal(
|
||||
text.trim(),
|
||||
descriptions[index].trim(),
|
||||
"it has the correct copy"
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("PM topic notification level descriptions", {
|
||||
template:
|
||||
"{{topic-notifications-options value=topic.details.notification_level topic=topic}}",
|
||||
|
||||
beforeEach() {
|
||||
this.set("topic", buildTopic("private_message"));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await selectKit().expand();
|
||||
|
||||
const uiTexts = extractDescs(selectKit().rows());
|
||||
const descriptions = getTranslations("_pm");
|
||||
|
||||
assert.equal(
|
||||
uiTexts.length,
|
||||
descriptions.length,
|
||||
"it has the correct copy"
|
||||
);
|
||||
|
||||
uiTexts.forEach((text, index) => {
|
||||
assert.equal(
|
||||
text.trim(),
|
||||
descriptions[index].trim(),
|
||||
"it has the correct copy"
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user