2019-10-30 21:48:24 +08:00
import { run } from "@ember/runloop";
2019-06-06 16:47:10 +08:00
import selectKit from "helpers/select-kit-helper";
2018-12-12 17:21:51 +08:00
import { acceptance } from "helpers/qunit-helpers";
import { toggleCheckDraftPopup } from "discourse/controllers/composer";
2015-04-02 02:18:46 +08:00
2016-07-27 17:50:13 +08:00
acceptance("Composer", {
loggedIn: true,
2018-12-12 17:21:51 +08:00
pretend(server, helper) {
server.get("/draft.json", () => {
return helper.response({
draft: null,
draft_sequence: 42
});
});
2019-02-27 18:46:16 +08:00
server.post("/uploads/lookup-urls", () => {
return helper.response([]);
});
2018-12-12 17:21:51 +08:00
},
2016-07-27 17:50:13 +08:00
settings: {
enable_whispers: true
}
});
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
QUnit.test("Tests the Composer controls", async assert => {
await visit("/");
assert.ok(exists("#create-topic"), "the create button is visible");
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await click("#create-topic");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
assert.ok(
exists(".title-input .popup-tip.bad.hide"),
"title errors are hidden by default"
);
assert.ok(
exists(".d-editor-textarea-wrapper .popup-tip.bad.hide"),
"body errors are hidden by default"
);
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await click("a.toggle-preview");
assert.ok(
!exists(".d-editor-preview:visible"),
"clicking the toggle hides the preview"
);
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await click("a.toggle-preview");
assert.ok(
exists(".d-editor-preview:visible"),
"clicking the toggle shows the preview again"
);
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await click("#reply-control button.create");
assert.ok(
!exists(".title-input .popup-tip.bad.hide"),
"it shows the empty title error"
);
assert.ok(
!exists(".d-editor-wrapper .popup-tip.bad.hide"),
"it shows the empty body error"
);
2015-11-19 02:35:18 +08:00
2018-07-19 17:40:42 +08:00
await fillIn("#reply-title", "this is my new topic title");
assert.ok(exists(".title-input .popup-tip.good"), "the title is now good");
2015-11-19 01:35:17 +08:00
2018-07-19 17:40:42 +08:00
await fillIn(".d-editor-input", "this is the *content* of a post");
assert.equal(
find(".d-editor-preview")
.html()
.trim(),
"<p>this is the <em>content</em> of a post</p>",
"it previews content"
);
assert.ok(
exists(".d-editor-textarea-wrapper .popup-tip.good"),
"the body is now good"
);
2015-11-19 01:35:17 +08:00
2018-07-19 17:40:42 +08:00
const textarea = find("#reply-control .d-editor-input")[0];
textarea.selectionStart = textarea.value.length;
textarea.selectionEnd = textarea.value.length;
// Testing keyboard events is tough!
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
const event = document.createEvent("Event");
event.initEvent("keydown", true, true);
event[mac ? "metaKey" : "ctrlKey"] = true;
event.keyCode = 66;
2019-10-30 21:48:24 +08:00
run(() => textarea.dispatchEvent(event));
2018-07-19 17:40:42 +08:00
const example = I18n.t(`composer.bold_text`);
assert.equal(
find("#reply-control .d-editor-input")
.val()
.trim(),
`this is the *content* of a post**${example}**`,
"it supports keyboard shortcuts"
);
2015-11-19 01:35:17 +08:00
2018-07-19 17:40:42 +08:00
await click("#reply-control a.cancel");
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await click(".modal-footer a:eq(1)");
assert.ok(!exists(".bootbox.modal"), "the confirmation can be cancelled");
2015-04-02 02:18:46 +08:00
});
2019-04-29 10:32:48 +08:00
QUnit.test("Composer upload placeholder", async assert => {
await visit("/");
await click("#create-topic");
const file1 = new Blob([""], { type: "image/png" });
file1.name = "test.png";
const data1 = {
files: [file1],
result: {
original_filename: "test.png",
thumbnail_width: 200,
thumbnail_height: 300,
url: "/uploads/test1.ext"
}
};
const file2 = new Blob([""], { type: "image/png" });
file2.name = "test.png";
const data2 = {
files: [file2],
result: {
original_filename: "test.png",
thumbnail_width: 100,
thumbnail_height: 200,
url: "/uploads/test2.ext"
}
};
const file3 = new Blob([""], { type: "image/png" });
file3.name = "image.png";
const data3 = {
files: [file3],
result: {
original_filename: "image.png",
thumbnail_width: 300,
thumbnail_height: 400,
url: "/uploads/test3.ext"
}
};
const file4 = new Blob([""], { type: "image/png" });
file4.name = "ima++ge.png";
const data4 = {
files: [file4],
result: {
original_filename: "ima++ge.png",
thumbnail_width: 300,
thumbnail_height: 400,
url: "/uploads/test3.ext"
}
};
await find(".wmd-controls").trigger("fileuploadsend", data1);
assert.equal(find(".d-editor-input").val(), "[Uploading: test.png...]() ");
await find(".wmd-controls").trigger("fileuploadsend", data2);
assert.equal(
find(".d-editor-input").val(),
"[Uploading: test.png...]() [Uploading: test.png(1)...]() "
);
await find(".wmd-controls").trigger("fileuploadsend", data4);
assert.equal(
find(".d-editor-input").val(),
"[Uploading: test.png...]() [Uploading: test.png(1)...]() [Uploading: ima++ge.png...]() ",
"should accept files with unescaped characters"
);
await find(".wmd-controls").trigger("fileuploadsend", data3);
assert.equal(
find(".d-editor-input").val(),
"[Uploading: test.png...]() [Uploading: test.png(1)...]() [Uploading: ima++ge.png...]() [Uploading: image.png...]() "
);
await find(".wmd-controls").trigger("fileuploaddone", data2);
assert.equal(
find(".d-editor-input").val(),
"[Uploading: test.png...]() ![test|100x200](/uploads/test2.ext) [Uploading: ima++ge.png...]() [Uploading: image.png...]() "
);
await find(".wmd-controls").trigger("fileuploaddone", data3);
assert.equal(
find(".d-editor-input").val(),
"[Uploading: test.png...]() ![test|100x200](/uploads/test2.ext) [Uploading: ima++ge.png...]() ![image|300x400](/uploads/test3.ext) "
);
await find(".wmd-controls").trigger("fileuploaddone", data1);
assert.equal(
find(".d-editor-input").val(),
"![test|200x300](/uploads/test1.ext) ![test|100x200](/uploads/test2.ext) [Uploading: ima++ge.png...]() ![image|300x400](/uploads/test3.ext) "
);
});
2018-10-03 09:12:36 +08:00
2018-07-19 17:40:42 +08:00
QUnit.test("Create a topic with server side errors", async assert => {
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "this title triggers an error");
await fillIn(".d-editor-input", "this is the *content* of a post");
await click("#reply-control button.create");
assert.ok(exists(".bootbox.modal"), "it pops up an error message");
await click(".bootbox.modal a.btn-primary");
assert.ok(!exists(".bootbox.modal"), "it dismisses the error");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
2015-04-02 02:18:46 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test("Create a Topic", async assert => {
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "Internationalization Localization");
await fillIn(".d-editor-input", "this is the *content* of a new topic post");
await click("#reply-control button.create");
assert.equal(
currentURL(),
"/t/internationalization-localization/280",
"it transitions to the newly created topic URL"
);
2015-04-02 02:18:46 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test("Create an enqueued Topic", async assert => {
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "Internationalization Localization");
await fillIn(".d-editor-input", "enqueue this content please");
await click("#reply-control button.create");
assert.ok(visible(".d-modal"), "it pops up a modal");
assert.equal(currentURL(), "/", "it doesn't change routes");
await click(".modal-footer button");
assert.ok(invisible(".d-modal"), "the modal can be dismissed");
2015-04-10 06:33:37 +08:00
});
2019-11-29 22:30:54 +08:00
QUnit.test("Can display a message and route to a URL", async assert => {
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "This title doesn't matter");
await fillIn(".d-editor-input", "custom message");
await click("#reply-control button.create");
assert.equal(
find(".bootbox .modal-body").text(),
"This is a custom response"
);
assert.equal(currentURL(), "/", "it doesn't change routes");
await click(".bootbox .btn-primary");
assert.equal(
currentURL(),
"/faq",
"can navigate to a `route_to` destination"
);
});
2018-07-19 17:40:42 +08:00
QUnit.test("Create a Reply", async assert => {
await visit("/t/internationalization-localization/280");
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
assert.ok(
!exists("article[data-post-id=12345]"),
"the post is not in the DOM"
);
2015-04-10 06:33:37 +08:00
2018-07-19 17:40:42 +08:00
await click("#topic-footer-buttons .btn.create");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
assert.ok(!exists("#reply-title"), "there is no title since this is a reply");
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await fillIn(".d-editor-input", "this is the content of my reply");
await click("#reply-control button.create");
assert.equal(
find(".cooked:last p").text(),
2019-10-12 03:33:34 +08:00
"If you use gettext format you could leverage Launchpad 13 translations and the community behind it."
2018-07-19 17:40:42 +08:00
);
2015-04-10 06:33:37 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test("Posting on a different topic", async assert => {
await visit("/t/internationalization-localization/280");
await click("#topic-footer-buttons .btn.create");
await fillIn(".d-editor-input", "this is the content for a different topic");
await visit("/t/1-3-0beta9-no-rate-limit-popups/28830");
assert.equal(currentURL(), "/t/1-3-0beta9-no-rate-limit-popups/28830");
await click("#reply-control button.create");
assert.ok(visible(".reply-where-modal"), "it pops up a modal");
await click(".btn-reply-here");
assert.equal(
find(".cooked:last p").text(),
2019-10-12 03:33:34 +08:00
"If you use gettext format you could leverage Launchpad 13 translations and the community behind it."
2018-07-19 17:40:42 +08:00
);
2015-05-15 06:18:12 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test("Create an enqueued Reply", async assert => {
await visit("/t/internationalization-localization/280");
2015-04-10 06:33:37 +08:00
2019-04-12 21:55:27 +08:00
assert.notOk(find(".pending-posts .reviewable-item").length);
2018-07-19 17:40:42 +08:00
await click("#topic-footer-buttons .btn.create");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
assert.ok(!exists("#reply-title"), "there is no title since this is a reply");
2015-04-10 06:33:37 +08:00
2018-07-19 17:40:42 +08:00
await fillIn(".d-editor-input", "enqueue this content please");
await click("#reply-control button.create");
assert.ok(
find(".cooked:last p").text() !== "enqueue this content please",
"it doesn't insert the post"
);
2015-04-10 06:33:37 +08:00
2018-07-19 17:40:42 +08:00
assert.ok(visible(".d-modal"), "it pops up a modal");
2015-04-10 06:33:37 +08:00
2018-07-19 17:40:42 +08:00
await click(".modal-footer button");
assert.ok(invisible(".d-modal"), "the modal can be dismissed");
2019-04-12 21:55:27 +08:00
assert.ok(find(".pending-posts .reviewable-item").length);
2015-04-02 02:18:46 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test("Edit the first post", async assert => {
await visit("/t/internationalization-localization/280");
2015-04-02 02:18:46 +08:00
2017-06-15 01:57:58 +08:00
assert.ok(
!exists(".topic-post:eq(0) .post-info.edits"),
"it has no edits icon at first"
);
2015-04-10 02:54:17 +08:00
2018-07-19 17:40:42 +08:00
await click(".topic-post:eq(0) button.show-more-actions");
await click(".topic-post:eq(0) button.edit");
assert.equal(
find(".d-editor-input")
.val()
.indexOf("Any plans to support"),
0,
"it populates the input with the post text"
);
2015-04-02 02:18:46 +08:00
2018-07-19 17:40:42 +08:00
await fillIn(".d-editor-input", "This is the new text for the post");
await fillIn("#reply-title", "This is the new text for the title");
await click("#reply-control button.create");
assert.ok(!exists(".d-editor-input"), "it closes the composer");
assert.ok(
exists(".topic-post:eq(0) .post-info.edits"),
"it has the edits icon"
);
assert.ok(
find("#topic-title h1")
.text()
.indexOf("This is the new text for the title") !== -1,
"it shows the new title"
);
assert.ok(
find(".topic-post:eq(0) .cooked")
.text()
.indexOf("This is the new text for the post") !== -1,
"it updates the post"
);
2015-04-02 02:18:46 +08:00
});
2015-04-10 06:33:37 +08:00
2018-07-19 17:40:42 +08:00
QUnit.test("Composer can switch between edits", async assert => {
await visit("/t/this-is-a-test-topic/9");
2015-08-14 00:49:13 +08:00
2018-07-19 17:40:42 +08:00
await click(".topic-post:eq(0) button.edit");
assert.equal(
find(".d-editor-input")
.val()
.indexOf("This is the first post."),
0,
"it populates the input with the post text"
);
await click(".topic-post:eq(1) button.edit");
assert.equal(
find(".d-editor-input")
.val()
.indexOf("This is the second post."),
0,
"it populates the input with the post text"
);
2015-08-14 00:49:13 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test(
"Composer with dirty edit can toggle to another edit",
async assert => {
await visit("/t/this-is-a-test-topic/9");
2015-08-24 22:55:56 +08:00
2018-07-19 17:40:42 +08:00
await click(".topic-post:eq(0) button.edit");
await fillIn(".d-editor-input", "This is a dirty reply");
await click(".topic-post:eq(1) button.edit");
2017-06-15 01:57:58 +08:00
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
2018-07-19 17:40:42 +08:00
await click(".modal-footer a:eq(0)");
2017-06-15 01:57:58 +08:00
assert.equal(
find(".d-editor-input")
.val()
.indexOf("This is the second post."),
0,
"it populates the input with the post text"
);
2018-07-19 17:40:42 +08:00
}
);
QUnit.test("Composer can toggle between edit and reply", async assert => {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:eq(0) button.edit");
assert.equal(
find(".d-editor-input")
.val()
.indexOf("This is the first post."),
0,
"it populates the input with the post text"
);
await click(".topic-post:eq(0) button.reply");
assert.equal(find(".d-editor-input").val(), "", "it clears the input");
await click(".topic-post:eq(0) button.edit");
assert.equal(
find(".d-editor-input")
.val()
.indexOf("This is the first post."),
0,
"it populates the input with the post text"
);
2015-08-24 22:55:56 +08:00
});
2018-09-18 17:31:23 +08:00
QUnit.test("Composer can toggle whispers", async assert => {
2018-11-29 23:16:34 +08:00
const menu = selectKit(".toolbar-popup-menu-options");
2018-09-18 17:31:23 +08:00
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:eq(0) button.reply");
2018-11-29 23:16:34 +08:00
await menu.expand();
await menu.selectRowByValue("toggleWhisper");
2018-09-18 17:31:23 +08:00
assert.ok(
2019-01-22 19:02:02 +08:00
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 1,
2018-09-18 17:31:23 +08:00
"it sets the post type to whisper"
);
2018-11-29 23:16:34 +08:00
await menu.expand();
await menu.selectRowByValue("toggleWhisper");
2018-09-18 17:31:23 +08:00
assert.ok(
2019-01-22 19:02:02 +08:00
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0,
2018-09-18 17:31:23 +08:00
"it removes the whisper mode"
);
2018-11-29 23:16:34 +08:00
await menu.expand();
await menu.selectRowByValue("toggleWhisper");
await click(".toggle-fullscreen");
2020-02-03 21:22:14 +08:00
await menu.expand();
2018-11-29 23:16:34 +08:00
assert.ok(
menu.rowByValue("toggleWhisper").exists(),
"whisper toggling is still present when going fullscreen"
);
2018-09-18 17:31:23 +08:00
});
2018-12-08 06:45:13 +08:00
QUnit.test(
"Composer can toggle layouts (open, fullscreen and draft)",
async assert => {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:eq(0) button.reply");
assert.ok(
find("#reply-control.open").length === 1,
"it starts in open state by default"
);
await click(".toggle-fullscreen");
assert.ok(
find("#reply-control.fullscreen").length === 1,
"it expands composer to full screen"
);
await click(".toggle-fullscreen");
assert.ok(
find("#reply-control.open").length === 1,
"it collapses composer to regular size"
);
await fillIn(".d-editor-input", "This is a dirty reply");
await click(".toggler");
assert.ok(
find("#reply-control.draft").length === 1,
"it collapses composer to draft bar"
);
await click(".toggle-fullscreen");
assert.ok(
find("#reply-control.open").length === 1,
"from draft, it expands composer back to open state"
);
}
);
2018-07-19 17:40:42 +08:00
QUnit.test(
"Composer can toggle between reply and createTopic",
async assert => {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:eq(0) button.reply");
2015-08-14 00:49:13 +08:00
2018-07-30 04:51:32 +08:00
await selectKit(".toolbar-popup-menu-options").expand();
await selectKit(".toolbar-popup-menu-options").selectRowByValue(
2018-07-19 17:40:42 +08:00
"toggleWhisper"
2017-06-15 01:57:58 +08:00
);
2015-08-14 00:49:13 +08:00
2017-06-15 01:57:58 +08:00
assert.ok(
2019-01-22 19:02:02 +08:00
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 1,
2016-07-27 17:50:13 +08:00
"it sets the post type to whisper"
);
2018-07-19 17:40:42 +08:00
await visit("/");
2017-06-15 01:57:58 +08:00
assert.ok(exists("#create-topic"), "the create topic button is visible");
2016-07-27 17:50:13 +08:00
2018-07-19 17:40:42 +08:00
await click("#create-topic");
2017-06-15 01:57:58 +08:00
assert.ok(
2019-01-22 19:02:02 +08:00
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0,
2016-07-27 17:50:13 +08:00
"it should reset the state of the composer's model"
);
2018-07-30 04:51:32 +08:00
await selectKit(".toolbar-popup-menu-options").expand();
await selectKit(".toolbar-popup-menu-options").selectRowByValue(
2018-07-19 17:40:42 +08:00
"toggleInvisible"
);
2017-12-13 17:49:32 +08:00
2017-06-15 01:57:58 +08:00
assert.ok(
2016-07-27 17:50:13 +08:00
find(".composer-fields .whisper")
.text()
.indexOf(I18n.t("composer.unlist")) > 0,
"it sets the topic to unlisted"
);
2018-07-19 17:40:42 +08:00
await visit("/t/this-is-a-test-topic/9");
2016-07-27 17:50:13 +08:00
2018-07-19 17:40:42 +08:00
await click(".topic-post:eq(0) button.reply");
2017-06-15 01:57:58 +08:00
assert.ok(
2016-07-27 17:50:13 +08:00
find(".composer-fields .whisper")
.text()
.indexOf(I18n.t("composer.unlist")) === -1,
"it should reset the state of the composer's model"
);
2018-07-19 17:40:42 +08:00
}
);
QUnit.test("Composer with dirty reply can toggle to edit", async assert => {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:eq(0) button.reply");
await fillIn(".d-editor-input", "This is a dirty reply");
await click(".topic-post:eq(0) button.edit");
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
await click(".modal-footer a:eq(0)");
assert.equal(
find(".d-editor-input")
.val()
.indexOf("This is the first post."),
0,
"it populates the input with the post text"
);
2015-08-14 00:49:13 +08:00
});
2018-07-19 17:40:42 +08:00
QUnit.test(
"Composer draft with dirty reply can toggle to edit",
async assert => {
await visit("/t/this-is-a-test-topic/9");
2015-08-14 00:49:13 +08:00
2018-07-19 17:40:42 +08:00
await click(".topic-post:eq(0) button.reply");
await fillIn(".d-editor-input", "This is a dirty reply");
await click(".toggler");
2019-07-04 23:45:57 +08:00
await click(".topic-post:eq(1) button.edit");
2017-06-15 01:57:58 +08:00
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
2019-07-04 23:45:57 +08:00
assert.equal(
find(".modal-footer a:eq(1)").text(),
I18n.t("post.abandon.no_value")
);
2018-07-19 17:40:42 +08:00
await click(".modal-footer a:eq(0)");
2017-06-15 01:57:58 +08:00
assert.equal(
find(".d-editor-input")
.val()
2019-07-04 23:45:57 +08:00
.indexOf("This is the second post."),
2017-06-15 01:57:58 +08:00
0,
"it populates the input with the post text"
);
2018-07-19 17:40:42 +08:00
}
);
2018-04-11 07:31:20 +08:00
2019-07-04 23:45:57 +08:00
QUnit.test(
"Composer draft can switch to draft in new context without destroying current draft",
async assert => {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:eq(0) button.reply");
await fillIn(".d-editor-input", "This is a dirty reply");
await click("#site-logo");
await click("#create-topic");
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
assert.equal(
find(".modal-footer a:eq(1)").text(),
I18n.t("post.abandon.no_save_draft")
);
await click(".modal-footer a:eq(1)");
assert.equal(
find(".d-editor-input").val(),
"",
"it populates the input with the post text"
);
}
);
2018-12-12 17:21:51 +08:00
QUnit.test("Checks for existing draft", async assert => {
2019-05-28 11:40:21 +08:00
try {
toggleCheckDraftPopup(true);
2018-04-11 07:31:20 +08:00
2019-05-28 11:40:21 +08:00
// prettier-ignore
server.get("/draft.json", () => { // eslint-disable-line no-undef
return [ 200, { "Content-Type": "application/json" }, {
draft: "{\"reply\":\"This is a draft of the first post\",\"action\":\"reply\",\"categoryId\":1,\"archetypeId\":\"regular\",\"metaData\":null,\"composerTime\":2863,\"typingTime\":200}",
draft_sequence: 42
} ];
});
2018-04-11 07:31:20 +08:00
2019-05-28 11:40:21 +08:00
await visit("/t/internationalization-localization/280");
2018-04-11 07:31:20 +08:00
2019-05-28 11:40:21 +08:00
await click(".topic-post:eq(0) button.show-more-actions");
await click(".topic-post:eq(0) button.edit");
2018-04-11 07:31:20 +08:00
2019-05-28 11:40:21 +08:00
assert.equal(find(".modal-body").text(), I18n.t("drafts.abandon.confirm"));
2018-04-11 07:31:20 +08:00
2019-05-28 11:40:21 +08:00
await click(".modal-footer .btn.btn-default");
} finally {
toggleCheckDraftPopup(false);
}
2018-04-11 07:31:20 +08:00
});
2019-02-27 18:46:16 +08:00
2019-03-28 04:55:09 +08:00
QUnit.test("Can switch states without abandon popup", async assert => {
2019-05-28 11:40:21 +08:00
try {
toggleCheckDraftPopup(true);
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
await visit("/t/internationalization-localization/280");
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
const longText = "a".repeat(256);
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
await click(".btn-primary.create.btn");
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
await fillIn(".d-editor-input", longText);
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
// prettier-ignore
server.get("/draft.json", () => { // eslint-disable-line no-undef
return [ 200, { "Content-Type": "application/json" }, {
draft: "{\"reply\":\"This is a draft of the first post\",\"action\":\"reply\",\"categoryId\":1,\"archetypeId\":\"regular\",\"metaData\":null,\"composerTime\":2863,\"typingTime\":200}",
draft_sequence: 42
} ];
});
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
await click("article#post_3 button.reply");
2019-03-28 04:55:09 +08:00
2020-02-03 21:22:14 +08:00
const composerActions = selectKit(".composer-actions");
2019-05-28 11:40:21 +08:00
await composerActions.expand();
2020-02-03 21:22:14 +08:00
await composerActions.selectRowByValue("reply_as_private_message");
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
assert.equal(
find(".modal-body").text(),
"",
"abandon popup shouldn't come"
);
2019-03-28 04:55:09 +08:00
2020-02-03 21:22:14 +08:00
assert.ok(
find(".d-editor-input")
.val()
.includes(longText),
2019-05-28 11:40:21 +08:00
"entered text should still be there"
);
2019-03-28 04:55:09 +08:00
2019-05-28 11:40:21 +08:00
assert.ok(
find('.action-title a[href="/t/internationalization-localization/280"]'),
"mode should have changed"
);
2019-04-11 22:03:36 +08:00
2019-05-28 11:40:21 +08:00
assert.ok(find(".save-animation"), "save animation should show");
} finally {
toggleCheckDraftPopup(false);
}
2019-03-28 04:55:09 +08:00
});
2019-03-07 05:14:55 +08:00
QUnit.test("Loading draft also replaces the recipients", async assert => {
2019-05-28 11:40:21 +08:00
try {
toggleCheckDraftPopup(true);
// prettier-ignore
server.get("/draft.json", () => { // eslint-disable-line no-undef
return [ 200, { "Content-Type": "application/json" }, {
"draft":"{\"reply\":\"hello\",\"action\":\"privateMessage\",\"title\":\"hello\",\"categoryId\":null,\"archetypeId\":\"private_message\",\"metaData\":null,\"usernames\":\"codinghorror\",\"composerTime\":9159,\"typingTime\":2500}",
"draft_sequence":0
} ];
});
2019-03-07 05:14:55 +08:00
2019-05-28 11:40:21 +08:00
await visit("/u/charlie");
await click("button.compose-pm");
await click(".modal .btn-default");
2019-03-07 05:14:55 +08:00
2019-05-28 11:40:21 +08:00
assert.equal(find(".users-input .item:eq(0)").text(), "codinghorror");
} finally {
toggleCheckDraftPopup(false);
}
2019-03-07 05:14:55 +08:00
});
2019-04-02 12:54:53 +08:00
QUnit.test(
"Deleting the text content of the first post in a private message",
async assert => {
Discourse.SiteSettings.allow_uncategorized_topics = false;
await visit("/t/34");
await click("#post_1 .d-icon-ellipsis-h");
await click("#post_1 .d-icon-pencil-alt");
await fillIn(".d-editor-input", "");
assert.equal(
find(".d-editor-container textarea").attr("placeholder"),
I18n.t("composer.reply_placeholder"),
"it should not block because of missing category"
);
}
);
2019-02-27 18:46:16 +08:00
const assertImageResized = (assert, uploads) => {
assert.equal(
find(".d-editor-input").val(),
uploads.join("\n"),
"it resizes uploaded image"
);
};
QUnit.test("Image resizing buttons", async assert => {
await visit("/");
await click("#create-topic");
let uploads = [
2019-11-05 18:40:02 +08:00
// 0 Default markdown with dimensions- should work
2019-02-27 18:46:16 +08:00
"![test|690x313](upload://test.png)",
2019-11-05 18:40:02 +08:00
// 1 Image with scaling percentage, should work
"![test|690x313,50%](upload://test.png)",
// 2 image with scaling percentage and a proceeding whitespace, should work
"![test|690x313, 50%](upload://test.png)",
// 3 No dimensions, should not work
"![test](upload://test.jpeg)",
// 4 Wrapped in backquetes should not work
2019-02-27 18:46:16 +08:00
"`![test|690x313](upload://test.png)`",
2019-11-05 18:40:02 +08:00
// 5 html image - should not work
2019-02-27 18:46:16 +08:00
"<img src='http://someimage.jpg' wight='20' height='20'>",
2019-11-05 18:40:02 +08:00
// 6 two images one the same line, but both are syntactically correct - both should work
2019-02-27 18:46:16 +08:00
"![onTheSameLine1|200x200](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)",
2019-11-05 18:40:02 +08:00
// 7 & 8 Identical images - both should work
2019-02-27 18:46:16 +08:00
"![identicalImage|300x300](upload://identicalImage.png)",
2019-11-05 18:40:02 +08:00
"![identicalImage|300x300](upload://identicalImage.png)",
// 9 Image with whitespaces in alt - should work
"![image with spaces in alt|690x220](upload://test.png)",
// 10 Image with markdown title - should work
`![image|690x220](upload://test.png "image title")`,
// 11 bbcode - should not work
2020-02-06 23:19:24 +08:00
"[img]http://example.com/image.jpg[/img]",
// 12 Image with data attributes
"![test|foo=bar|690x313,50%|bar=baz](upload://test.png)"
2019-02-27 18:46:16 +08:00
];
await fillIn(".d-editor-input", uploads.join("\n"));
assert.ok(
2020-02-06 23:19:24 +08:00
find(".button-wrapper").length === 10,
2019-02-27 18:46:16 +08:00
"it adds correct amount of scaling button groups"
);
2019-11-05 18:40:02 +08:00
// Default
uploads[0] = "![test|690x313, 50%](upload://test.png)";
2019-11-13 04:32:37 +08:00
await click(
find(".button-wrapper[data-image-index='0'] .scale-btn[data-scale='50']")
);
2019-02-27 18:46:16 +08:00
assertImageResized(assert, uploads);
2019-11-05 18:40:02 +08:00
// Targets the correct image if two on the same line
uploads[6] =
"![onTheSameLine1|200x200, 50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)";
2019-11-13 04:32:37 +08:00
await click(
find(".button-wrapper[data-image-index='3'] .scale-btn[data-scale='50']")
);
2019-02-27 18:46:16 +08:00
assertImageResized(assert, uploads);
2019-11-05 18:40:02 +08:00
// Try the other image on the same line
uploads[6] =
"![onTheSameLine1|200x200, 50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250, 75%](upload://onTheSameLine2.jpeg)";
2019-11-13 04:32:37 +08:00
await click(
find(".button-wrapper[data-image-index='4'] .scale-btn[data-scale='75']")
);
2019-02-27 18:46:16 +08:00
assertImageResized(assert, uploads);
2019-11-05 18:40:02 +08:00
// Make sure we target the correct image if there are duplicates
uploads[7] = "![identicalImage|300x300, 50%](upload://identicalImage.png)";
2019-11-13 04:32:37 +08:00
await click(
find(".button-wrapper[data-image-index='5'] .scale-btn[data-scale='50']")
);
2019-02-27 18:46:16 +08:00
assertImageResized(assert, uploads);
2019-11-05 18:40:02 +08:00
// Try the other dupe
uploads[8] = "![identicalImage|300x300, 75%](upload://identicalImage.png)";
2019-11-13 04:32:37 +08:00
await click(
find(".button-wrapper[data-image-index='6'] .scale-btn[data-scale='75']")
);
2019-02-27 18:46:16 +08:00
assertImageResized(assert, uploads);
2019-11-05 18:40:02 +08:00
// Don't mess with image titles
uploads[10] = `![image|690x220, 75%](upload://test.png "image title")`;
2019-11-13 04:32:37 +08:00
await click(
find(".button-wrapper[data-image-index='8'] .scale-btn[data-scale='75']")
);
2019-02-27 18:46:16 +08:00
assertImageResized(assert, uploads);
2019-04-08 11:20:28 +08:00
2020-02-06 23:19:24 +08:00
// Keep data attributes
uploads[12] = `![test|foo=bar|690x313, 75%|bar=baz](upload://test.png)`;
await click(
find(".button-wrapper[data-image-index='9'] .scale-btn[data-scale='75']")
);
assertImageResized(assert, uploads);
2019-04-08 11:20:28 +08:00
await fillIn(
".d-editor-input",
`
![test|690x313](upload://test.png)
\`<script>alert("xss")</script>\`
`
);
assert.ok(
find("script").length === 0,
"it does not unescapes script tags in code blocks"
);
2019-02-27 18:46:16 +08:00
});
2020-01-07 21:33:48 +08:00
QUnit.test("can reply to a private message", async assert => {
let submitted;
/* global server */
server.post("/posts", () => {
submitted = true;
return [200, { "Content-Type": "application/json" }, {}];
});
await visit("/t/34");
await click(".topic-post:eq(0) button.reply");
await fillIn(".d-editor-input", "this is the *content* of the reply");
await click("#reply-control button.create");
assert.ok(submitted);
});