597 lines
16 KiB
JavaScript
597 lines
16 KiB
JavaScript
import EmberObject from "@ember/object";
|
|
import { Placeholder } from "discourse/lib/posts-with-placeholders";
|
|
import { Promise } from "rsvp";
|
|
import Topic from "discourse/models/topic";
|
|
import User from "discourse/models/user";
|
|
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
|
|
import { next } from "@ember/runloop";
|
|
import pretender from "discourse/tests/helpers/create-pretender";
|
|
import { settled } from "@ember/test-helpers";
|
|
import { test } from "qunit";
|
|
|
|
function topicWithStream(streamDetails) {
|
|
let topic = Topic.create();
|
|
topic.get("postStream").setProperties(streamDetails);
|
|
return topic;
|
|
}
|
|
|
|
discourseModule("Unit | Controller | topic", function (hooks) {
|
|
hooks.beforeEach(function () {
|
|
this.registry.injection("controller", "appEvents", "service:app-events");
|
|
});
|
|
|
|
hooks.afterEach(function () {
|
|
this.registry.unregister("current-user:main");
|
|
let topic = this.container.lookup("controller:topic");
|
|
topic.setProperties({
|
|
selectedPostIds: [],
|
|
selectedPostUsername: null,
|
|
currentUser: null,
|
|
});
|
|
});
|
|
|
|
test("editTopic", function (assert) {
|
|
const model = Topic.create();
|
|
const controller = this.getController("topic", { model });
|
|
assert.not(controller.get("editingTopic"), "we are not editing by default");
|
|
|
|
controller.set("model.details.can_edit", false);
|
|
controller.send("editTopic");
|
|
|
|
assert.not(
|
|
controller.get("editingTopic"),
|
|
"calling editTopic doesn't enable editing unless the user can edit"
|
|
);
|
|
|
|
controller.set("model.details.can_edit", true);
|
|
controller.send("editTopic");
|
|
|
|
assert.ok(
|
|
controller.get("editingTopic"),
|
|
"calling editTopic enables editing if the user can edit"
|
|
);
|
|
assert.strictEqual(controller.get("buffered.title"), model.get("title"));
|
|
assert.strictEqual(
|
|
controller.get("buffered.category_id"),
|
|
model.get("category_id")
|
|
);
|
|
|
|
controller.send("cancelEditingTopic");
|
|
|
|
assert.not(
|
|
controller.get("editingTopic"),
|
|
"cancelling edit mode reverts the property value"
|
|
);
|
|
});
|
|
|
|
test("deleteTopic", function (assert) {
|
|
const model = Topic.create();
|
|
let destroyed = false;
|
|
let modalDisplayed = false;
|
|
model.destroy = () => {
|
|
destroyed = true;
|
|
return Promise.resolve();
|
|
};
|
|
const controller = this.getController("topic", {
|
|
model,
|
|
siteSettings: {
|
|
min_topic_views_for_delete_confirm: 5,
|
|
},
|
|
deleteTopicModal: () => {
|
|
modalDisplayed = true;
|
|
},
|
|
});
|
|
|
|
model.set("views", 10000);
|
|
controller.send("deleteTopic");
|
|
assert.not(destroyed, "don't destroy popular topic");
|
|
assert.ok(modalDisplayed, "display confirmation modal for popular topic");
|
|
|
|
model.set("views", 3);
|
|
controller.send("deleteTopic");
|
|
assert.ok(destroyed, "destroy not popular topic");
|
|
});
|
|
|
|
test("toggleMultiSelect", async function (assert) {
|
|
const model = Topic.create();
|
|
const controller = this.getController("topic", { model });
|
|
|
|
assert.not(
|
|
controller.get("multiSelect"),
|
|
"multi selection mode is disabled by default"
|
|
);
|
|
|
|
controller.get("selectedPostIds").pushObject(1);
|
|
assert.strictEqual(controller.get("selectedPostIds.length"), 1);
|
|
|
|
controller.send("toggleMultiSelect");
|
|
await settled();
|
|
|
|
assert.ok(
|
|
controller.get("multiSelect"),
|
|
"calling 'toggleMultiSelect' once enables multi selection mode"
|
|
);
|
|
assert.strictEqual(
|
|
controller.get("selectedPostIds.length"),
|
|
0,
|
|
"toggling 'multiSelect' clears 'selectedPostIds'"
|
|
);
|
|
|
|
controller.get("selectedPostIds").pushObject(2);
|
|
assert.strictEqual(controller.get("selectedPostIds.length"), 1);
|
|
|
|
controller.send("toggleMultiSelect");
|
|
await settled();
|
|
|
|
assert.not(
|
|
controller.get("multiSelect"),
|
|
"calling 'toggleMultiSelect' twice disables multi selection mode"
|
|
);
|
|
assert.strictEqual(
|
|
controller.get("selectedPostIds.length"),
|
|
0,
|
|
"toggling 'multiSelect' clears 'selectedPostIds'"
|
|
);
|
|
});
|
|
|
|
test("selectedPosts", function (assert) {
|
|
let model = topicWithStream({ posts: [{ id: 1 }, { id: 2 }, { id: 3 }] });
|
|
const controller = this.getController("topic", { model });
|
|
|
|
controller.set("selectedPostIds", [1, 2, 42]);
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPosts.length"),
|
|
2,
|
|
"selectedPosts only contains already loaded posts"
|
|
);
|
|
assert.not(
|
|
controller.get("selectedPosts").some((p) => p === undefined),
|
|
"selectedPosts only contains valid post objects"
|
|
);
|
|
});
|
|
|
|
test("selectedAllPosts", function (assert) {
|
|
let model = topicWithStream({ stream: [1, 2, 3] });
|
|
const controller = this.getController("topic", { model });
|
|
|
|
controller.set("selectedPostIds", [1, 2]);
|
|
|
|
assert.not(
|
|
controller.get("selectedAllPosts"),
|
|
"not all posts are selected"
|
|
);
|
|
|
|
controller.get("selectedPostIds").pushObject(3);
|
|
|
|
assert.ok(controller.get("selectedAllPosts"), "all posts are selected");
|
|
|
|
controller.get("selectedPostIds").pushObject(42);
|
|
|
|
assert.ok(
|
|
controller.get("selectedAllPosts"),
|
|
"all posts (including filtered posts) are selected"
|
|
);
|
|
|
|
model.setProperties({
|
|
"postStream.isMegaTopic": true,
|
|
posts_count: 1,
|
|
});
|
|
|
|
assert.ok(
|
|
controller.get("selectedAllPosts"),
|
|
"it uses the topic's post count for megatopics"
|
|
);
|
|
});
|
|
|
|
test("selectedPostsUsername", function (assert) {
|
|
let model = topicWithStream({
|
|
posts: [
|
|
{ id: 1, username: "gary" },
|
|
{ id: 2, username: "gary" },
|
|
{ id: 3, username: "lili" },
|
|
],
|
|
stream: [1, 2, 3],
|
|
});
|
|
const controller = this.getController("topic", { model });
|
|
const selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsUsername"),
|
|
undefined,
|
|
"no username when no selected posts"
|
|
);
|
|
|
|
selectedPostIds.pushObject(1);
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsUsername"),
|
|
"gary",
|
|
"username of the selected posts"
|
|
);
|
|
|
|
selectedPostIds.pushObject(2);
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsUsername"),
|
|
"gary",
|
|
"username of all the selected posts when same user"
|
|
);
|
|
|
|
selectedPostIds.pushObject(3);
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsUsername"),
|
|
undefined,
|
|
"no username when more than 1 user"
|
|
);
|
|
|
|
selectedPostIds.replace(2, 1, [42]);
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsUsername"),
|
|
undefined,
|
|
"no username when not already loaded posts are selected"
|
|
);
|
|
});
|
|
|
|
test("showSelectedPostsAtBottom", function (assert) {
|
|
const site = EmberObject.create({ mobileView: false });
|
|
const model = Topic.create({ posts_count: 3 });
|
|
const controller = this.getController("topic", { model, site });
|
|
|
|
assert.not(controller.get("showSelectedPostsAtBottom"), "false on desktop");
|
|
|
|
site.set("mobileView", true);
|
|
|
|
assert.not(
|
|
controller.get("showSelectedPostsAtBottom"),
|
|
"requires at least 3 posts on mobile"
|
|
);
|
|
|
|
model.set("posts_count", 4);
|
|
|
|
assert.ok(
|
|
controller.get("showSelectedPostsAtBottom"),
|
|
"true when mobile and more than 3 posts"
|
|
);
|
|
});
|
|
|
|
test("canDeleteSelected", function (assert) {
|
|
const currentUser = User.create({ admin: false });
|
|
this.registry.register("current-user:main", currentUser, {
|
|
instantiate: false,
|
|
});
|
|
this.registry.injection("controller", "currentUser", "current-user:main");
|
|
let model = topicWithStream({
|
|
posts: [
|
|
{ id: 1, can_delete: false },
|
|
{ id: 2, can_delete: true },
|
|
{ id: 3, can_delete: true },
|
|
],
|
|
stream: [1, 2, 3],
|
|
});
|
|
const controller = this.getController("topic", {
|
|
model,
|
|
currentUser,
|
|
});
|
|
const selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.not(
|
|
controller.get("canDeleteSelected"),
|
|
"false when no posts are selected"
|
|
);
|
|
|
|
selectedPostIds.pushObject(1);
|
|
|
|
assert.not(
|
|
controller.get("canDeleteSelected"),
|
|
"false when can't delete one of the selected posts"
|
|
);
|
|
|
|
selectedPostIds.replace(0, 1, [2, 3]);
|
|
|
|
assert.ok(
|
|
controller.get("canDeleteSelected"),
|
|
"true when all selected posts can be deleted"
|
|
);
|
|
|
|
selectedPostIds.pushObject(1);
|
|
|
|
assert.not(
|
|
controller.get("canDeleteSelected"),
|
|
"false when all posts are selected and user is staff"
|
|
);
|
|
|
|
currentUser.set("admin", true);
|
|
|
|
assert.ok(
|
|
controller.get("canDeleteSelected"),
|
|
"true when all posts are selected and user is staff"
|
|
);
|
|
});
|
|
|
|
test("Can split/merge topic", function (assert) {
|
|
let model = topicWithStream({
|
|
posts: [
|
|
{ id: 1, post_number: 1, post_type: 1 },
|
|
{ id: 2, post_number: 2, post_type: 4 },
|
|
{ id: 3, post_number: 3, post_type: 1 },
|
|
],
|
|
stream: [1, 2, 3],
|
|
});
|
|
model.set("details.can_move_posts", false);
|
|
const controller = this.getController("topic", { model });
|
|
const selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.not(
|
|
controller.get("canMergeTopic"),
|
|
"can't merge topic when no posts are selected"
|
|
);
|
|
|
|
selectedPostIds.pushObject(1);
|
|
|
|
assert.not(
|
|
controller.get("canMergeTopic"),
|
|
"can't merge topic when can't move posts"
|
|
);
|
|
|
|
model.set("details.can_move_posts", true);
|
|
|
|
assert.ok(controller.get("canMergeTopic"), "can merge topic");
|
|
|
|
selectedPostIds.removeObject(1);
|
|
selectedPostIds.pushObject(2);
|
|
|
|
assert.ok(
|
|
controller.get("canMergeTopic"),
|
|
"can merge topic when 1st post is not a regular post"
|
|
);
|
|
|
|
selectedPostIds.pushObject(3);
|
|
|
|
assert.ok(
|
|
controller.get("canMergeTopic"),
|
|
"can merge topic when all posts are selected"
|
|
);
|
|
});
|
|
|
|
test("canChangeOwner", function (assert) {
|
|
const currentUser = User.create({ admin: false });
|
|
this.registry.register("current-user:main", currentUser, {
|
|
instantiate: false,
|
|
});
|
|
this.registry.injection("controller", "currentUser", "current-user:main");
|
|
|
|
let model = topicWithStream({
|
|
posts: [
|
|
{ id: 1, username: "gary" },
|
|
{ id: 2, username: "lili" },
|
|
],
|
|
stream: [1, 2],
|
|
});
|
|
model.set("currentUser", { admin: false });
|
|
const controller = this.getController("topic", {
|
|
model,
|
|
currentUser,
|
|
});
|
|
const selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.not(
|
|
controller.get("canChangeOwner"),
|
|
"false when no posts are selected"
|
|
);
|
|
|
|
selectedPostIds.pushObject(1);
|
|
|
|
assert.not(controller.get("canChangeOwner"), "false when not admin");
|
|
|
|
currentUser.set("admin", true);
|
|
|
|
assert.ok(
|
|
controller.get("canChangeOwner"),
|
|
"true when admin and one post is selected"
|
|
);
|
|
|
|
selectedPostIds.pushObject(2);
|
|
|
|
assert.not(
|
|
controller.get("canChangeOwner"),
|
|
"false when admin but more than 1 user"
|
|
);
|
|
});
|
|
|
|
test("canMergePosts", function (assert) {
|
|
let model = topicWithStream({
|
|
posts: [
|
|
{ id: 1, username: "gary", can_delete: true },
|
|
{ id: 2, username: "lili", can_delete: true },
|
|
{ id: 3, username: "gary", can_delete: false },
|
|
{ id: 4, username: "gary", can_delete: true },
|
|
],
|
|
stream: [1, 2, 3],
|
|
});
|
|
const controller = this.getController("topic", {
|
|
model,
|
|
});
|
|
const selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.not(
|
|
controller.get("canMergePosts"),
|
|
"false when no posts are selected"
|
|
);
|
|
|
|
selectedPostIds.pushObject(1);
|
|
|
|
assert.not(
|
|
controller.get("canMergePosts"),
|
|
"false when only one post is selected"
|
|
);
|
|
|
|
selectedPostIds.pushObject(2);
|
|
|
|
assert.not(
|
|
controller.get("canMergePosts"),
|
|
"false when selected posts are from different users"
|
|
);
|
|
|
|
selectedPostIds.replace(1, 1, [3]);
|
|
|
|
assert.not(
|
|
controller.get("canMergePosts"),
|
|
"false when selected posts can't be deleted"
|
|
);
|
|
|
|
selectedPostIds.replace(1, 1, [4]);
|
|
|
|
assert.ok(
|
|
controller.get("canMergePosts"),
|
|
"true when all selected posts are deletable and by the same user"
|
|
);
|
|
});
|
|
|
|
test("Select/deselect all", function (assert) {
|
|
let model = topicWithStream({ stream: [1, 2, 3] });
|
|
const controller = this.getController("topic", { model });
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsCount"),
|
|
0,
|
|
"no posts selected by default"
|
|
);
|
|
|
|
controller.send("selectAll");
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsCount"),
|
|
3,
|
|
"calling 'selectAll' selects all posts"
|
|
);
|
|
|
|
controller.send("deselectAll");
|
|
|
|
assert.strictEqual(
|
|
controller.get("selectedPostsCount"),
|
|
0,
|
|
"calling 'deselectAll' deselects all posts"
|
|
);
|
|
});
|
|
|
|
test("togglePostSelection", function (assert) {
|
|
const controller = this.getController("topic");
|
|
const selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.strictEqual(
|
|
selectedPostIds[0],
|
|
undefined,
|
|
"no posts selected by default"
|
|
);
|
|
|
|
controller.send("togglePostSelection", { id: 1 });
|
|
|
|
assert.strictEqual(
|
|
selectedPostIds[0],
|
|
1,
|
|
"adds the selected post id if not already selected"
|
|
);
|
|
|
|
controller.send("togglePostSelection", { id: 1 });
|
|
|
|
assert.strictEqual(
|
|
selectedPostIds[0],
|
|
undefined,
|
|
"removes the selected post id if already selected"
|
|
);
|
|
});
|
|
|
|
test("selectBelow", function (assert) {
|
|
const site = EmberObject.create({
|
|
post_types: { small_action: 3, whisper: 4 },
|
|
});
|
|
let model = topicWithStream({
|
|
stream: [1, 2, 3, 4, 5, 6, 7, 8],
|
|
posts: [
|
|
{ id: 5, cooked: "whisper post", post_type: 4 },
|
|
{ id: 6, cooked: "a small action", post_type: 3 },
|
|
{ id: 7, cooked: "", post_type: 4 },
|
|
],
|
|
});
|
|
const controller = this.getController("topic", { site, model });
|
|
let selectedPostIds = controller.get("selectedPostIds");
|
|
|
|
assert.strictEqual(
|
|
selectedPostIds[0],
|
|
undefined,
|
|
"no posts selected by default"
|
|
);
|
|
|
|
controller.send("selectBelow", { id: 3 });
|
|
|
|
assert.strictEqual(selectedPostIds[0], 3, "selected post #3");
|
|
assert.strictEqual(
|
|
selectedPostIds[1],
|
|
4,
|
|
"also selected 1st post below post #3"
|
|
);
|
|
assert.strictEqual(
|
|
selectedPostIds[2],
|
|
5,
|
|
"also selected 2nd post below post #3"
|
|
);
|
|
assert.strictEqual(
|
|
selectedPostIds[3],
|
|
8,
|
|
"also selected 3rd post below post #3"
|
|
);
|
|
});
|
|
|
|
test("topVisibleChanged", function (assert) {
|
|
let model = topicWithStream({
|
|
posts: [{ id: 1 }],
|
|
});
|
|
const controller = this.getController("topic", { model });
|
|
const placeholder = new Placeholder("post-placeholder");
|
|
|
|
assert.strictEqual(
|
|
controller.send("topVisibleChanged", {
|
|
post: placeholder,
|
|
}),
|
|
undefined,
|
|
"it should work with a post-placeholder"
|
|
);
|
|
});
|
|
|
|
test("deletePost - no modal is shown if post does not have replies", function (assert) {
|
|
pretender.get("/posts/2/reply-ids.json", () => {
|
|
return [200, { "Content-Type": "application/json" }, []];
|
|
});
|
|
|
|
let destroyed;
|
|
const post = EmberObject.create({
|
|
id: 2,
|
|
post_number: 2,
|
|
can_delete: true,
|
|
reply_count: 3,
|
|
destroy: () => {
|
|
destroyed = true;
|
|
return Promise.resolve();
|
|
},
|
|
});
|
|
|
|
const currentUser = EmberObject.create({ moderator: true });
|
|
let model = topicWithStream({
|
|
stream: [2, 3, 4],
|
|
posts: [post, { id: 3 }, { id: 4 }],
|
|
});
|
|
const controller = this.getController("topic", { model, currentUser });
|
|
|
|
const done = assert.async();
|
|
controller.send("deletePost", post);
|
|
|
|
next(() => {
|
|
assert.ok(destroyed, "post was destroyed");
|
|
done();
|
|
});
|
|
});
|
|
});
|