Robin Ward f5d391a48a
REFACTOR: Move app-events:main to service:app-events (#8152)
AppEvents was always a service object in disguise, so we should move it
to the correct place in the application. Doing this allows other service
objects to inject it easily without container access.

In the future we should also deprecate `this.appEvents` without an
explicit injection too.
2019-10-04 10:06:08 -04:00

553 lines
14 KiB
JavaScript

import Topic from "discourse/models/topic";
import PostStream from "discourse/models/post-stream";
import { Placeholder } from "discourse/lib/posts-with-placeholders";
moduleFor("controller:topic", "controller:topic", {
needs: [
"controller:composer",
"controller:application",
"service:app-events"
],
beforeEach() {
this.registry.injection("controller", "appEvents", "service:app-events");
}
});
QUnit.test("editTopic", function(assert) {
const model = Topic.create();
const controller = this.subject({ 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.equal(controller.get("buffered.title"), model.get("title"));
assert.equal(
controller.get("buffered.category_id"),
model.get("category_id")
);
controller.send("cancelEditingTopic");
assert.not(
controller.get("editingTopic"),
"cancelling edit mode reverts the property value"
);
});
QUnit.test("toggleMultiSelect", function(assert) {
const model = Topic.create();
const controller = this.subject({ model });
assert.not(
controller.get("multiSelect"),
"multi selection mode is disabled by default"
);
controller.get("selectedPostIds").pushObject(1);
assert.equal(controller.get("selectedPostIds.length"), 1);
controller.send("toggleMultiSelect");
assert.ok(
controller.get("multiSelect"),
"calling 'toggleMultiSelect' once enables multi selection mode"
);
assert.equal(
controller.get("selectedPostIds.length"),
0,
"toggling 'multiSelect' clears 'selectedPostIds'"
);
controller.get("selectedPostIds").pushObject(2);
assert.equal(controller.get("selectedPostIds.length"), 1);
controller.send("toggleMultiSelect");
assert.not(
controller.get("multiSelect"),
"calling 'toggleMultiSelect' twice disables multi selection mode"
);
assert.equal(
controller.get("selectedPostIds.length"),
0,
"toggling 'multiSelect' clears 'selectedPostIds'"
);
});
QUnit.test("selectedPosts", function(assert) {
const postStream = { posts: [{ id: 1 }, { id: 2 }, { id: 3 }] };
const model = Topic.create({ postStream });
const controller = this.subject({ model });
controller.set("selectedPostIds", [1, 2, 42]);
assert.equal(
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"
);
});
QUnit.test("selectedAllPosts", function(assert) {
const postStream = { stream: [1, 2, 3] };
const model = Topic.create({ postStream });
const controller = this.subject({ 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"
);
});
QUnit.test("selectedPostsUsername", function(assert) {
const postStream = {
posts: [
{ id: 1, username: "gary" },
{ id: 2, username: "gary" },
{ id: 3, username: "lili" }
],
stream: [1, 2, 3]
};
const model = Topic.create({ postStream });
const controller = this.subject({ model });
const selectedPostIds = controller.get("selectedPostIds");
assert.equal(
controller.get("selectedPostsUsername"),
undefined,
"no username when no selected posts"
);
selectedPostIds.pushObject(1);
assert.equal(
controller.get("selectedPostsUsername"),
"gary",
"username of the selected posts"
);
selectedPostIds.pushObject(2);
assert.equal(
controller.get("selectedPostsUsername"),
"gary",
"username of all the selected posts when same user"
);
selectedPostIds.pushObject(3);
assert.equal(
controller.get("selectedPostsUsername"),
undefined,
"no username when more than 1 user"
);
selectedPostIds.replace(2, 1, [42]);
assert.equal(
controller.get("selectedPostsUsername"),
undefined,
"no username when not already loaded posts are selected"
);
});
QUnit.test("showSelectedPostsAtBottom", function(assert) {
const site = Ember.Object.create({ mobileView: false });
const model = Topic.create({ posts_count: 3 });
const controller = this.subject({ 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"
);
});
QUnit.test("canDeleteSelected", function(assert) {
const postStream = {
posts: [
{ id: 1, can_delete: false },
{ id: 2, can_delete: true },
{ id: 3, can_delete: true }
],
stream: [1, 2, 3]
};
const currentUser = Discourse.User.create({ admin: false });
this.registry.register("current-user:main", currentUser, {
instantiate: false
});
this.registry.injection("controller", "currentUser", "current-user:main");
const model = Topic.create({ postStream });
const controller = this.subject({ model });
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"
);
});
QUnit.test("Can split/merge topic", function(assert) {
const postStream = {
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]
};
const model = Topic.create({
postStream,
details: { can_move_posts: false }
});
const controller = this.subject({ 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"
);
});
QUnit.test("canChangeOwner", function(assert) {
const currentUser = Discourse.User.create({ admin: false });
this.registry.register("current-user:main", currentUser, {
instantiate: false
});
this.registry.injection("controller", "currentUser", "current-user:main");
const postStream = {
posts: [{ id: 1, username: "gary" }, { id: 2, username: "lili" }],
stream: [1, 2]
};
const model = Topic.create({ postStream, currentUser: { admin: false } });
const controller = this.subject({ model });
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"
);
});
QUnit.test("canMergePosts", function(assert) {
const postStream = {
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 model = Topic.create({ postStream });
const controller = this.subject({ 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"
);
});
QUnit.test("Select/deselect all", function(assert) {
const postStream = { stream: [1, 2, 3] };
const model = Topic.create({ postStream });
const controller = this.subject({ model });
assert.equal(
controller.get("selectedPostsCount"),
0,
"no posts selected by default"
);
controller.send("selectAll");
assert.equal(
controller.get("selectedPostsCount"),
postStream.stream.length,
"calling 'selectAll' selects all posts"
);
controller.send("deselectAll");
assert.equal(
controller.get("selectedPostsCount"),
0,
"calling 'deselectAll' deselects all posts"
);
});
QUnit.test("togglePostSelection", function(assert) {
const controller = this.subject();
const selectedPostIds = controller.get("selectedPostIds");
assert.equal(selectedPostIds[0], undefined, "no posts selected by default");
controller.send("togglePostSelection", { id: 1 });
assert.equal(
selectedPostIds[0],
1,
"adds the selected post id if not already selected"
);
controller.send("togglePostSelection", { id: 1 });
assert.equal(
selectedPostIds[0],
undefined,
"removes the selected post id if already selected"
);
});
// QUnit.test("selectReplies", function(assert) {
// const controller = this.subject();
// const selectedPostIds = controller.get("selectedPostIds");
//
// assert.equal(selectedPostIds[0], undefined, "no posts selected by default");
//
// controller.send("selectReplies", { id: 42 });
//
// assert.equal(selectedPostIds[0], 42, "selected post #42");
// assert.equal(selectedPostIds[1], 45, "selected post #45");
// assert.equal(selectedPostIds[2], 100, "selected post #100");
// });
QUnit.test("selectBelow", function(assert) {
const site = Ember.Object.create({
post_types: { small_action: 3, whisper: 4 }
});
const postStream = {
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 model = Topic.create({ postStream });
const controller = this.subject({ site, model });
let selectedPostIds = controller.get("selectedPostIds");
assert.equal(selectedPostIds[0], undefined, "no posts selected by default");
controller.send("selectBelow", { id: 3 });
assert.equal(selectedPostIds[0], 3, "selected post #3");
assert.equal(selectedPostIds[1], 4, "also selected 1st post below post #3");
assert.equal(selectedPostIds[2], 5, "also selected 2nd post below post #3");
assert.equal(selectedPostIds[3], 8, "also selected 3rd post below post #3");
});
QUnit.test("topVisibleChanged", function(assert) {
const postStream = PostStream.create({
posts: [{ id: 1 }]
});
const model = Topic.create({ postStream });
const controller = this.subject({ model });
const placeholder = new Placeholder("post-placeholder");
assert.equal(
controller.send("topVisibleChanged", {
post: placeholder
}),
null,
"it should work with a post-placehodler"
);
});
QUnit.test(
"deletePost - no modal is shown if post does not have replies",
function(assert) {
/* global server */
server.get("/posts/2/reply-ids.json", () => {
return [200, { "Content-Type": "application/json" }, []];
});
let destroyed;
const post = Ember.Object.create({
id: 2,
post_number: 2,
can_delete: true,
reply_count: 3,
destroy: () => {
destroyed = true;
return Ember.RSVP.Promise.resolve();
}
});
const postStream = Ember.Object.create({
stream: [2, 3, 4],
posts: [post, { id: 3 }, { id: 4 }]
});
const currentUser = Ember.Object.create({ moderator: true });
const model = Topic.create({ postStream });
const controller = this.subject({ model, currentUser });
const done = assert.async();
controller.send("deletePost", post);
Ember.run.next(() => {
assert.ok(destroyed, "post was destroyed");
done();
});
}
);