Merge master
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { default as siteSettingFixture } from "fixtures/site_settings";
|
||||
import siteSettingFixture from "fixtures/site_settings";
|
||||
|
||||
var titleOverride = undefined;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ acceptance("Admin - Suspend User", {
|
||||
server.put("/admin/users/:user_id/suspend", () =>
|
||||
helper.response(200, {
|
||||
suspension: {
|
||||
suspended: true
|
||||
suspended_till: "2099-01-01T12:00:00.000Z"
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -16,7 +16,7 @@ acceptance("Admin - Suspend User", {
|
||||
server.put("/admin/users/:user_id/unsuspend", () =>
|
||||
helper.response(200, {
|
||||
suspension: {
|
||||
suspended: false
|
||||
suspended_till: null
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
|
||||
acceptance("Admin - User Index", {
|
||||
@@ -84,15 +85,10 @@ QUnit.test("will clear unsaved groups when switching user", async assert => {
|
||||
"the name should be correct"
|
||||
);
|
||||
|
||||
await fillIn(".admin-group-selector .filter-input", "Macdonald");
|
||||
await click(".admin-group-selector .filter-input");
|
||||
await keyEvent(".admin-group-selector .filter-input", "keydown", 13);
|
||||
|
||||
assert.equal(
|
||||
find('.admin-group-selector span[title="Macdonald"]').length,
|
||||
1,
|
||||
"group should be set"
|
||||
);
|
||||
const groupSelector = selectKit(".admin-group-selector");
|
||||
await groupSelector.expand();
|
||||
await groupSelector.selectRowByValue(42);
|
||||
assert.equal(groupSelector.header().value(), 42, "group should be set");
|
||||
|
||||
await visit("/admin/users/1/eviltrout");
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ QUnit.test("Can open the category modal", async assert => {
|
||||
await click(".edit-category");
|
||||
assert.ok(visible(".d-modal"), "it pops up a modal");
|
||||
|
||||
await click("a.close");
|
||||
await click("button.modal-close");
|
||||
assert.ok(!visible(".d-modal"), "it closes the modal");
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ QUnit.test("Editing the category", async assert => {
|
||||
assert.ok(!visible(".d-modal"), "it closes the modal");
|
||||
assert.equal(
|
||||
DiscourseURL.redirectedTo,
|
||||
"/c/bug",
|
||||
"/c/bug/1",
|
||||
"it does one of the rare full page redirects"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ QUnit.test("category hashtag is cooked properly", async assert => {
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
await fillIn(".d-editor-input", "this is a category hashtag #bug");
|
||||
|
||||
// TODO: Test that the autocomplete shows
|
||||
assert.equal(
|
||||
find(".d-editor-preview:visible")
|
||||
@@ -14,12 +15,4 @@ QUnit.test("category hashtag is cooked properly", async assert => {
|
||||
.trim(),
|
||||
'<p>this is a category hashtag <a href="/c/bugs" class="hashtag">#<span>bug</span></a></p>'
|
||||
);
|
||||
|
||||
await click("#reply-control .btn.create");
|
||||
assert.equal(
|
||||
find(".topic-post:last .cooked p")
|
||||
.html()
|
||||
.trim(),
|
||||
'this is a category hashtag <a href="/c/bugs" class="hashtag">#<span>bug</span></a>'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,9 +7,9 @@ QUnit.test("Do not track mentions", async assert => {
|
||||
server.post("/clicks/track", () => assert.ok(false));
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
assert.ok(invisible("#user-card"), "card should not appear");
|
||||
assert.ok(invisible(".user-card"), "card should not appear");
|
||||
|
||||
await click("article[data-post-id=3651] a.mention");
|
||||
assert.ok(visible("#user-card"), "card should appear");
|
||||
assert.ok(visible(".user-card"), "card should appear");
|
||||
assert.equal(currentURL(), "/t/internationalization-localization/280");
|
||||
});
|
||||
|
||||
@@ -2,6 +2,8 @@ import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import { _clearSnapshots } from "select-kit/components/composer-actions";
|
||||
import { toggleCheckDraftPopup } from "discourse/controllers/composer";
|
||||
import Draft from "discourse/models/draft";
|
||||
import { Promise } from "rsvp";
|
||||
|
||||
acceptance("Composer Actions", {
|
||||
loggedIn: true,
|
||||
@@ -99,6 +101,9 @@ QUnit.test("replying to post - toggle_whisper", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("replying to post - reply_as_new_topic", async assert => {
|
||||
sandbox
|
||||
.stub(Draft, "get")
|
||||
.returns(Promise.resolve({ draft: "", draft_sequence: 0 }));
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
const categoryChooser = selectKit(".title-wrapper .category-chooser");
|
||||
const categoryChooserReplyArea = selectKit(".reply-area .category-chooser");
|
||||
@@ -129,46 +134,16 @@ QUnit.test("replying to post - reply_as_new_topic", async assert => {
|
||||
.val()
|
||||
.includes(quote)
|
||||
);
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
QUnit.test("shared draft", async assert => {
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
const tags = selectKit(".mini-tag-chooser");
|
||||
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
await fillIn(
|
||||
"#reply-title",
|
||||
"This is the new text for the title using 'quotes'"
|
||||
);
|
||||
|
||||
await fillIn(".d-editor-input", "This is the new text for the post");
|
||||
await tags.expand();
|
||||
await tags.selectRowByValue("monkey");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("shared_draft");
|
||||
|
||||
assert.equal(tags.header().value(), "monkey", "tags are not reset");
|
||||
|
||||
assert.equal(
|
||||
find("#reply-title").val(),
|
||||
"This is the new text for the title using 'quotes'"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find("#reply-control .btn-primary.create .d-button-label").text(),
|
||||
I18n.t("composer.create_shared_draft")
|
||||
);
|
||||
|
||||
assert.ok(find("#reply-control.composing-shared-draft").length === 1);
|
||||
await click(".modal-footer .btn.btn-default");
|
||||
} finally {
|
||||
toggleCheckDraftPopup(false);
|
||||
}
|
||||
QUnit.test("reply_as_new_topic without a new_topic draft", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".create.reply");
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_as_new_topic");
|
||||
assert.equal(exists(find(".bootbox")), false);
|
||||
});
|
||||
|
||||
QUnit.test("hide component if no content", async assert => {
|
||||
@@ -305,7 +280,7 @@ QUnit.test("replying to post - toggle_topic_bump", async assert => {
|
||||
QUnit.test("replying to post as staff", async assert => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ staff: true, admin: false });
|
||||
updateCurrentUser({ admin: true });
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_3 button.reply");
|
||||
await composerActions.expand();
|
||||
@@ -317,7 +292,7 @@ QUnit.test("replying to post as staff", async assert => {
|
||||
QUnit.test("replying to post as TL3 user", async assert => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ staff: false, admin: false, trust_level: 3 });
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 3 });
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_3 button.reply");
|
||||
await composerActions.expand();
|
||||
@@ -335,7 +310,7 @@ QUnit.test("replying to post as TL3 user", async assert => {
|
||||
QUnit.test("replying to post as TL4 user", async assert => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ staff: false, admin: false, trust_level: 4 });
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 4 });
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_3 button.reply");
|
||||
await composerActions.expand();
|
||||
@@ -363,3 +338,78 @@ QUnit.test(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
acceptance("Composer Actions With New Topic Draft", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
enable_whispers: true
|
||||
},
|
||||
site: {
|
||||
can_tag_topics: true
|
||||
},
|
||||
beforeEach() {
|
||||
_clearSnapshots();
|
||||
},
|
||||
pretend(server, helper) {
|
||||
server.get("draft.json", () => {
|
||||
return helper.response({
|
||||
draft:
|
||||
'{"reply":"dum de dum da ba.","action":"createTopic","title":"dum da ba dum dum","categoryId":null,"archetypeId":"regular","metaData":null,"composerTime":540879,"typingTime":3400}',
|
||||
draft_sequence: 0
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("shared draft", async assert => {
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
const tags = selectKit(".mini-tag-chooser");
|
||||
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
await fillIn(
|
||||
"#reply-title",
|
||||
"This is the new text for the title using 'quotes'"
|
||||
);
|
||||
|
||||
await fillIn(".d-editor-input", "This is the new text for the post");
|
||||
await tags.expand();
|
||||
await tags.selectRowByValue("monkey");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("shared_draft");
|
||||
|
||||
assert.equal(tags.header().value(), "monkey", "tags are not reset");
|
||||
|
||||
assert.equal(
|
||||
find("#reply-title").val(),
|
||||
"This is the new text for the title using 'quotes'"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find("#reply-control .btn-primary.create .d-button-label").text(),
|
||||
I18n.t("composer.create_shared_draft")
|
||||
);
|
||||
|
||||
assert.ok(find("#reply-control.composing-shared-draft").length === 1);
|
||||
await click(".modal-footer .btn.btn-default");
|
||||
} finally {
|
||||
toggleCheckDraftPopup(false);
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("reply_as_new_topic with new_topic draft", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".create.reply");
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_as_new_topic");
|
||||
assert.equal(
|
||||
find(".bootbox .modal-body").text(),
|
||||
I18n.t("composer.composer_actions.reply_as_new_topic.confirm")
|
||||
);
|
||||
await click(".modal-footer .btn.btn-default");
|
||||
});
|
||||
|
||||
@@ -34,6 +34,6 @@ QUnit.test("attachments are cooked properly", async assert => {
|
||||
find(".d-editor-preview:visible")
|
||||
.html()
|
||||
.trim(),
|
||||
'<p><a href="/uploads/short-url/asdsad.png" class="attachment">test</a></p>'
|
||||
'<p><a class="attachment" href="/uploads/short-url/asdsad.png">test</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
|
||||
acceptance("Composer - Hyperlink", {
|
||||
loggedIn: true
|
||||
});
|
||||
|
||||
QUnit.test("add a hyperlink to a reply", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:first-child button.reply");
|
||||
await fillIn(".d-editor-input", "This is a link to ");
|
||||
|
||||
assert.ok(
|
||||
!exists(".insert-link.modal-body"),
|
||||
"no hyperlink modal by default"
|
||||
);
|
||||
|
||||
await click(".d-editor button.link");
|
||||
assert.ok(exists(".insert-link.modal-body"), "hyperlink modal visible");
|
||||
|
||||
await fillIn(".modal-body .link-url", "google.com");
|
||||
await fillIn(".modal-body .link-text", "Google");
|
||||
await click(".modal-footer button.btn-primary");
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"This is a link to [Google](http://google.com)",
|
||||
"adds link with url and text, prepends 'http://'"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".insert-link.modal-body"),
|
||||
"modal dismissed after submitting link"
|
||||
);
|
||||
|
||||
await fillIn(".d-editor-input", "Reset textarea contents.");
|
||||
|
||||
await click(".d-editor button.link");
|
||||
await fillIn(".modal-body .link-url", "google.com");
|
||||
await fillIn(".modal-body .link-text", "Google");
|
||||
await click(".modal-footer button.btn-danger");
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"Reset textarea contents.",
|
||||
"adds link with url and text, prepends 'http://'"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".insert-link.modal-body"),
|
||||
"modal dismissed after cancelling"
|
||||
);
|
||||
|
||||
const textarea = find("#reply-control .d-editor-input")[0];
|
||||
textarea.selectionStart = 0;
|
||||
textarea.selectionEnd = 6;
|
||||
await click(".d-editor button.link");
|
||||
|
||||
await fillIn(".modal-body .link-url", "somelink.com");
|
||||
await click(".modal-footer button.btn-primary");
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"[Reset](http://somelink.com) textarea contents.",
|
||||
"adds link to a selected text"
|
||||
);
|
||||
|
||||
await fillIn(".d-editor-input", "");
|
||||
|
||||
await click(".d-editor button.link");
|
||||
await fillIn(".modal-body .link-url", "http://google.com");
|
||||
await keyEvent(".modal-body .link-url", "keyup", 32);
|
||||
assert.ok(
|
||||
!exists(".internal-link-results"),
|
||||
"does not show internal links search dropdown when inputting a url"
|
||||
);
|
||||
|
||||
await fillIn(".modal-body .link-url", "local");
|
||||
await keyEvent(".modal-body .link-url", "keyup", 32);
|
||||
assert.ok(
|
||||
exists(".internal-link-results"),
|
||||
"shows internal links search dropdown when entering keywords"
|
||||
);
|
||||
|
||||
await keyEvent(".insert-link", "keydown", 40);
|
||||
await keyEvent(".insert-link", "keydown", 13);
|
||||
|
||||
assert.ok(
|
||||
!exists(".internal-link-results"),
|
||||
"search dropdown dismissed after selecting an internal link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".link-url")
|
||||
.val()
|
||||
.includes("http"),
|
||||
"replaces link url field with internal link"
|
||||
);
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
import { run } from "@ember/runloop";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { toggleCheckDraftPopup } from "discourse/controllers/composer";
|
||||
@@ -84,7 +85,7 @@ QUnit.test("Tests the Composer controls", async assert => {
|
||||
event[mac ? "metaKey" : "ctrlKey"] = true;
|
||||
event.keyCode = 66;
|
||||
|
||||
Ember.run(() => textarea.dispatchEvent(event));
|
||||
run(() => textarea.dispatchEvent(event));
|
||||
|
||||
const example = I18n.t(`composer.bold_text`);
|
||||
assert.equal(
|
||||
@@ -233,6 +234,26 @@ QUnit.test("Create an enqueued Topic", async assert => {
|
||||
assert.ok(invisible(".d-modal"), "the modal can be dismissed");
|
||||
});
|
||||
|
||||
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"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Create a Reply", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
@@ -249,7 +270,7 @@ QUnit.test("Create a Reply", async assert => {
|
||||
await click("#reply-control button.create");
|
||||
assert.equal(
|
||||
find(".cooked:last p").text(),
|
||||
"this is the content of my reply"
|
||||
"If you use gettext format you could leverage Launchpad 13 translations and the community behind it."
|
||||
);
|
||||
});
|
||||
|
||||
@@ -266,7 +287,7 @@ QUnit.test("Posting on a different topic", async assert => {
|
||||
await click(".btn-reply-here");
|
||||
assert.equal(
|
||||
find(".cooked:last p").text(),
|
||||
"this is the content for a different topic"
|
||||
"If you use gettext format you could leverage Launchpad 13 translations and the community behind it."
|
||||
);
|
||||
});
|
||||
|
||||
@@ -426,50 +447,14 @@ QUnit.test("Composer can toggle whispers", async assert => {
|
||||
|
||||
await click(".toggle-fullscreen");
|
||||
|
||||
await menu.expand();
|
||||
|
||||
assert.ok(
|
||||
menu.rowByValue("toggleWhisper").exists(),
|
||||
"whisper toggling is still present when going fullscreen"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Switching composer whisper state", async assert => {
|
||||
const menu = selectKit(".toolbar-popup-menu-options");
|
||||
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
|
||||
await menu.expand();
|
||||
await menu.selectRowByValue("toggleWhisper");
|
||||
|
||||
await fillIn(".d-editor-input", "this is the content of my reply");
|
||||
await click("#reply-control button.create");
|
||||
|
||||
assert.ok(find(".topic-post:last").hasClass("whisper"));
|
||||
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0,
|
||||
"doesn’t set topic reply as whisper"
|
||||
);
|
||||
|
||||
await click(".topic-post:last button.reply");
|
||||
|
||||
assert.ok(find(".topic-post:last").hasClass("whisper"));
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 1,
|
||||
"sets post reply as a whisper"
|
||||
);
|
||||
|
||||
await click(".topic-post:nth-last-child(2) button.reply");
|
||||
|
||||
assert.notOk(find(".topic-post:nth-last-child(2)").hasClass("whisper"));
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0,
|
||||
"doesn’t set post reply as a whisper"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Composer can toggle layouts (open, fullscreen and draft)",
|
||||
async assert => {
|
||||
@@ -586,19 +571,48 @@ QUnit.test(
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".toggler");
|
||||
await click(".topic-post:eq(0) button.edit");
|
||||
await click(".topic-post:eq(1) button.edit");
|
||||
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_value")
|
||||
);
|
||||
await click(".modal-footer a:eq(0)");
|
||||
assert.equal(
|
||||
find(".d-editor-input")
|
||||
.val()
|
||||
.indexOf("This is the first post."),
|
||||
.indexOf("This is the second post."),
|
||||
0,
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
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"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("Checks for existing draft", async assert => {
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
@@ -626,7 +640,6 @@ QUnit.test("Checks for existing draft", async assert => {
|
||||
|
||||
QUnit.test("Can switch states without abandon popup", async assert => {
|
||||
try {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
toggleCheckDraftPopup(true);
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@@ -647,8 +660,9 @@ QUnit.test("Can switch states without abandon popup", async assert => {
|
||||
|
||||
await click("article#post_3 button.reply");
|
||||
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_to_topic");
|
||||
await composerActions.selectRowByValue("reply_as_private_message");
|
||||
|
||||
assert.equal(
|
||||
find(".modal-body").text(),
|
||||
@@ -656,9 +670,10 @@ QUnit.test("Can switch states without abandon popup", async assert => {
|
||||
"abandon popup shouldn't come"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
longText,
|
||||
assert.ok(
|
||||
find(".d-editor-input")
|
||||
.val()
|
||||
.includes(longText),
|
||||
"entered text should still be there"
|
||||
);
|
||||
|
||||
@@ -729,66 +744,89 @@ QUnit.test("Image resizing buttons", async assert => {
|
||||
await click("#create-topic");
|
||||
|
||||
let uploads = [
|
||||
// 0 Default markdown with dimensions- should work
|
||||
"",
|
||||
"[img]http://example.com/image.jpg[/img]",
|
||||
"",
|
||||
"",
|
||||
// 1 Image with scaling percentage, should work
|
||||
"",
|
||||
// 2 image with scaling percentage and a proceeding whitespace, should work
|
||||
"",
|
||||
// 3 No dimensions, should not work
|
||||
"",
|
||||
// 4 Wrapped in backquetes should not work
|
||||
"``",
|
||||
"",
|
||||
// 5 html image - should not work
|
||||
"<img src='http://someimage.jpg' wight='20' height='20'>",
|
||||
// 6 two images one the same line, but both are syntactically correct - both should work
|
||||
" ",
|
||||
// 7 & 8 Identical images - both should work
|
||||
"",
|
||||
""
|
||||
"",
|
||||
// 9 Image with whitespaces in alt - should work
|
||||
"",
|
||||
// 10 Image with markdown title - should work
|
||||
``,
|
||||
// 11 bbcode - should not work
|
||||
"[img]http://example.com/image.jpg[/img]",
|
||||
// 12 Image with data attributes
|
||||
""
|
||||
];
|
||||
|
||||
await fillIn(".d-editor-input", uploads.join("\n"));
|
||||
|
||||
assert.ok(
|
||||
find(".button-wrapper").length === 0,
|
||||
"it does not append scaling buttons before hovering images"
|
||||
);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
|
||||
assert.ok(
|
||||
find(".button-wrapper").length === 6,
|
||||
find(".button-wrapper").length === 10,
|
||||
"it adds correct amount of scaling button groups"
|
||||
);
|
||||
|
||||
uploads[0] = "";
|
||||
await click(find(".button-wrapper .scale-btn[data-scale='50']")[0]);
|
||||
// Default
|
||||
uploads[0] = "";
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='0'] .scale-btn[data-scale='50']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
|
||||
uploads[2] = "";
|
||||
await click(find(".button-wrapper .scale-btn[data-scale='75']")[1]);
|
||||
// Targets the correct image if two on the same line
|
||||
uploads[6] =
|
||||
" ";
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='3'] .scale-btn[data-scale='50']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
|
||||
uploads[7] =
|
||||
" ";
|
||||
await click(find(".button-wrapper .scale-btn[data-scale='50']")[2]);
|
||||
// Try the other image on the same line
|
||||
uploads[6] =
|
||||
" ";
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='4'] .scale-btn[data-scale='75']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
|
||||
uploads[7] =
|
||||
" ";
|
||||
await click(find(".button-wrapper .scale-btn[data-scale='75']")[3]);
|
||||
// Make sure we target the correct image if there are duplicates
|
||||
uploads[7] = "";
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='5'] .scale-btn[data-scale='50']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
|
||||
uploads[8] = "";
|
||||
await click(find(".button-wrapper .scale-btn[data-scale='50']")[4]);
|
||||
// Try the other dupe
|
||||
uploads[8] = "";
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='6'] .scale-btn[data-scale='75']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
// Don't mess with image titles
|
||||
uploads[10] = ``;
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='8'] .scale-btn[data-scale='75']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
uploads[9] = "";
|
||||
await click(find(".button-wrapper .scale-btn[data-scale='75']")[5]);
|
||||
// Keep data attributes
|
||||
uploads[12] = ``;
|
||||
await click(
|
||||
find(".button-wrapper[data-image-index='9'] .scale-btn[data-scale='75']")
|
||||
);
|
||||
assertImageResized(assert, uploads);
|
||||
|
||||
await fillIn(
|
||||
@@ -800,10 +838,25 @@ QUnit.test("Image resizing buttons", async assert => {
|
||||
`
|
||||
);
|
||||
|
||||
await triggerEvent($(".d-editor-preview img"), "mouseover");
|
||||
|
||||
assert.ok(
|
||||
find("script").length === 0,
|
||||
"it does not unescapes script tags in code blocks"
|
||||
);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -156,7 +156,7 @@ acceptance("Composer topic featured links when uncategorized is not allowed", {
|
||||
});
|
||||
|
||||
QUnit.test("Pasting a link enables the text input area", async assert => {
|
||||
updateCurrentUser({ admin: false, staff: false, trust_level: 1 });
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 1 });
|
||||
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
@@ -18,7 +18,7 @@ acceptance("Composer and uncategorized is not allowed", {
|
||||
});
|
||||
|
||||
QUnit.test("Disable body until category is selected", async assert => {
|
||||
updateCurrentUser({ admin: false, staff: false, trust_level: 1 });
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 1 });
|
||||
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
@@ -48,7 +48,7 @@ QUnit.test("Disable body until category is selected", async assert => {
|
||||
|
||||
await fillIn(".d-editor-input", "Now I can type stuff");
|
||||
await categoryChooser.expand();
|
||||
await categoryChooser.selectRowByValue("__none__");
|
||||
await categoryChooser.selectRowByIndex(0);
|
||||
|
||||
assert.ok(
|
||||
find(".d-editor-textarea-wrapper.disabled").length === 0,
|
||||
|
||||
@@ -26,7 +26,7 @@ QUnit.test("shows banner when required", async assert => {
|
||||
"alert is displayed when email disabled for non-staff"
|
||||
);
|
||||
|
||||
updateCurrentUser({ staff: true, moderator: true });
|
||||
updateCurrentUser({ moderator: true });
|
||||
await visit("/");
|
||||
assert.ok(
|
||||
exists(".alert-emails-disabled"),
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { IMAGE_VERSION as v } from "pretty-text/emoji/version";
|
||||
import { resetCache } from "discourse/components/emoji-picker";
|
||||
|
||||
acceptance("EmojiPicker", {
|
||||
loggedIn: true,
|
||||
beforeEach() {
|
||||
resetCache();
|
||||
const store = Discourse.__container__.lookup("service:emoji-store");
|
||||
store.reset();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.skip("emoji picker can be opened/closed", async assert => {
|
||||
QUnit.test("emoji picker can be opened/closed", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
@@ -32,7 +32,7 @@ QUnit.skip("emoji picker can be opened/closed", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("emojis can be hovered to display info", async assert => {
|
||||
QUnit.test("emojis can be hovered to display info", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
@@ -47,7 +47,7 @@ QUnit.skip("emojis can be hovered to display info", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("emoji picker triggers event when picking emoji", async assert => {
|
||||
QUnit.test("emoji picker triggers event when picking emoji", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
await click("button.emoji.btn");
|
||||
@@ -60,7 +60,37 @@ QUnit.skip("emoji picker triggers event when picking emoji", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("emoji picker has a list of recently used emojis", async assert => {
|
||||
QUnit.test(
|
||||
"emoji picker adds leading whitespace before emoji",
|
||||
async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
// Whitespace should be added on text
|
||||
await fillIn(".d-editor-input", "This is a test input");
|
||||
await click("button.emoji.btn");
|
||||
await click(".emoji-picker button[title='grinning']");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"This is a test input :grinning:",
|
||||
"it adds the emoji code and a leading whitespace when there is text"
|
||||
);
|
||||
await click("button.emoji.btn");
|
||||
|
||||
// Whitespace should not be added on whitespace
|
||||
await fillIn(".d-editor-input", "This is a test input ");
|
||||
await click("button.emoji.btn");
|
||||
await click(".emoji-picker button[title='grinning']");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"This is a test input :grinning:",
|
||||
"it adds the emoji code and no leading whitespace when user already entered whitespace"
|
||||
);
|
||||
await click("button.emoji.btn");
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("emoji picker has a list of recently used emojis", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
await click("button.emoji.btn");
|
||||
@@ -106,7 +136,7 @@ QUnit.skip("emoji picker has a list of recently used emojis", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip(
|
||||
QUnit.test(
|
||||
"emoji picker correctly orders recently used emojis",
|
||||
async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@@ -134,7 +164,7 @@ QUnit.skip(
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.skip("emoji picker lazy loads emojis", async assert => {
|
||||
QUnit.test("emoji picker lazy loads emojis", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
@@ -147,7 +177,7 @@ QUnit.skip("emoji picker lazy loads emojis", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("emoji picker persists state", async assert => {
|
||||
QUnit.test("emoji picker persists state", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
|
||||
@@ -14,14 +14,6 @@ QUnit.test("emoji is cooked properly", async assert => {
|
||||
.trim(),
|
||||
`<p>this is an emoji <img src="/images/emoji/emoji_one/blonde_woman.png?v=${v}" title=":blonde_woman:" class="emoji" alt=":blonde_woman:"></p>`
|
||||
);
|
||||
|
||||
await click("#reply-control .btn.create");
|
||||
assert.equal(
|
||||
find(".topic-post:last .cooked p")
|
||||
.html()
|
||||
.trim(),
|
||||
`this is an emoji <img src="/images/emoji/emoji_one/blonde_woman.png?v=${v}" title=":blonde_woman:" class="emoji" alt=":blonde_woman:">`
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("skin toned emoji is cooked properly", async assert => {
|
||||
@@ -35,12 +27,4 @@ QUnit.test("skin toned emoji is cooked properly", async assert => {
|
||||
.trim(),
|
||||
`<p>this is an emoji <img src="/images/emoji/emoji_one/blonde_woman/5.png?v=${v}" title=":blonde_woman:t5:" class="emoji" alt=":blonde_woman:t5:"></p>`
|
||||
);
|
||||
|
||||
await click("#reply-control .btn.create");
|
||||
assert.equal(
|
||||
find(".topic-post:last .cooked p")
|
||||
.html()
|
||||
.trim(),
|
||||
`this is an emoji <img src="/images/emoji/emoji_one/blonde_woman/5.png?v=${v}" title=":blonde_woman:t5:" class="emoji" alt=":blonde_woman:t5:">`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
|
||||
acceptance("Enforce Second Factor", {
|
||||
loggedIn: true
|
||||
loggedIn: true,
|
||||
pretend(server, helper) {
|
||||
server.post("/u/second_factors.json", () => {
|
||||
return helper.response({
|
||||
success: "OK",
|
||||
password_required: "true"
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("as an admin", async assert => {
|
||||
@@ -27,7 +35,7 @@ QUnit.test("as an admin", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("as a user", async assert => {
|
||||
updateCurrentUser({ staff: false, admin: false });
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/u/eviltrout/preferences/second-factor");
|
||||
Discourse.SiteSettings.enforce_second_factor = "all";
|
||||
@@ -49,3 +57,28 @@ QUnit.test("as a user", async assert => {
|
||||
"it stays at second-factor preferences"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("as an anonymous user", async assert => {
|
||||
updateCurrentUser({ moderator: false, admin: false, is_anonymous: true });
|
||||
|
||||
await visit("/u/eviltrout/preferences/second-factor");
|
||||
Discourse.SiteSettings.enforce_second_factor = "all";
|
||||
Discourse.SiteSettings.allow_anonymous_posting = true;
|
||||
|
||||
await visit("/u/eviltrout/summary");
|
||||
|
||||
assert.notEqual(
|
||||
find(".control-label").text(),
|
||||
"Password",
|
||||
"it will transition from second-factor preferences"
|
||||
);
|
||||
|
||||
await click("#toggle-hamburger-menu");
|
||||
await click("a.about-link");
|
||||
|
||||
assert.notEqual(
|
||||
find(".control-label").text(),
|
||||
"Password",
|
||||
"it is possible to navigate to other pages"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4,14 +4,14 @@ import DiscourseURL from "discourse/lib/url";
|
||||
acceptance("Group Card - Mobile", { mobileView: true });
|
||||
|
||||
QUnit.skip("group card", async assert => {
|
||||
await visit("/t/301/1");
|
||||
await visit("/t/-/301/1");
|
||||
assert.ok(
|
||||
invisible("#group-card"),
|
||||
invisible(".group-card"),
|
||||
"mobile group card is invisible by default"
|
||||
);
|
||||
|
||||
await click("a.mention-group:first");
|
||||
assert.ok(visible("#group-card"), "mobile group card should appear");
|
||||
assert.ok(visible(".group-card"), "mobile group card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.group-page-link");
|
||||
|
||||
@@ -4,11 +4,11 @@ import DiscourseURL from "discourse/lib/url";
|
||||
acceptance("Group Card");
|
||||
|
||||
QUnit.test("group card", async assert => {
|
||||
await visit("/t/301/1");
|
||||
assert.ok(invisible("#group-card"), "user card is invisible by default");
|
||||
await visit("/t/-/301/1");
|
||||
assert.ok(invisible(".group-card"), "user card is invisible by default");
|
||||
|
||||
await click("a.mention-group:first");
|
||||
assert.ok(visible("#group-card"), "card should appear");
|
||||
assert.ok(visible(".group-card"), "card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.group-page-link");
|
||||
|
||||
@@ -26,7 +26,7 @@ QUnit.test("Viewing Members as anon user", async assert => {
|
||||
acceptance("Group Members", { loggedIn: true });
|
||||
|
||||
QUnit.test("Viewing Members as a group owner", async assert => {
|
||||
updateCurrentUser({ admin: false, staff: false });
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/g/discourse");
|
||||
await click(".group-members-add");
|
||||
|
||||
@@ -42,7 +42,7 @@ QUnit.test("As an admin", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("As a group owner", async assert => {
|
||||
updateCurrentUser({ admin: false, staff: false });
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
await visit("/g/discourse/manage/interaction");
|
||||
|
||||
assert.equal(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
|
||||
acceptance("Managing Group Membership", {
|
||||
loggedIn: true
|
||||
@@ -65,10 +66,17 @@ QUnit.test("As an admin", async assert => {
|
||||
1,
|
||||
"it should display the membership request template field"
|
||||
);
|
||||
|
||||
const emailDomains = selectKit(".group-form-automatic-membership-automatic");
|
||||
await emailDomains.expand();
|
||||
await emailDomains.fillInFilter("foo.com");
|
||||
await emailDomains.keyboard("enter");
|
||||
|
||||
assert.equal(emailDomains.header().value(), "foo.com");
|
||||
});
|
||||
|
||||
QUnit.test("As a group owner", async assert => {
|
||||
updateCurrentUser({ staff: false, admin: false });
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/g/discourse/manage/membership");
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ QUnit.test("As an admin", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("As a group owner", async assert => {
|
||||
updateCurrentUser({ staff: false, admin: false });
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/g/discourse/manage/profile");
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ acceptance("Group Requests", {
|
||||
is_group_user: true,
|
||||
is_group_owner: true,
|
||||
is_group_owner_display: true,
|
||||
can_see_members: true,
|
||||
mentionable: false,
|
||||
messageable: false
|
||||
},
|
||||
@@ -126,5 +127,8 @@ QUnit.test("Group Requests", async assert => {
|
||||
.trim(),
|
||||
"denied"
|
||||
);
|
||||
assert.deepEqual(requests, [["19", "true"], ["20", undefined]]);
|
||||
assert.deepEqual(requests, [
|
||||
["19", "true"],
|
||||
["20", undefined]
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -51,29 +51,22 @@ QUnit.test("Anonymous Viewing Group", async assert => {
|
||||
);
|
||||
assert.ok(count(".user-stream-item") > 0, "it lists stream items");
|
||||
|
||||
await selectKit(".group-dropdown").expand();
|
||||
const groupDropdown = selectKit(".group-dropdown");
|
||||
await groupDropdown.expand();
|
||||
|
||||
assert.equal(groupDropdown.rowByIndex(1).name(), "discourse");
|
||||
|
||||
assert.equal(
|
||||
find(".select-kit-row")
|
||||
.text()
|
||||
.trim(),
|
||||
"discourse",
|
||||
"it displays the right row"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find(".group-dropdown-filter")
|
||||
.text()
|
||||
.trim(),
|
||||
I18n.t("groups.index.all").toLowerCase(),
|
||||
"it displays the right header"
|
||||
groupDropdown.rowByIndex(0).name(),
|
||||
I18n.t("groups.index.all").toLowerCase()
|
||||
);
|
||||
|
||||
Discourse.SiteSettings.enable_group_directory = false;
|
||||
|
||||
await visit("/g");
|
||||
await visit("/g/discourse");
|
||||
await selectKit(".group-dropdown").expand();
|
||||
|
||||
await groupDropdown.expand();
|
||||
|
||||
assert.equal(
|
||||
find(".group-dropdown-filter").length,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { run } from "@ember/runloop";
|
||||
import { acceptance, controllerFor } from "helpers/qunit-helpers";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
acceptance("Modal");
|
||||
|
||||
QUnit.test("modal", async assert => {
|
||||
QUnit.test("modal", async function(assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
@@ -14,11 +15,15 @@ QUnit.test("modal", async assert => {
|
||||
await click(".login-button");
|
||||
assert.ok(find(".d-modal:visible").length === 1, "modal should appear");
|
||||
|
||||
let controller = controllerFor("modal");
|
||||
assert.equal(controller.name, "login");
|
||||
|
||||
await click(".modal-outer-container");
|
||||
assert.ok(
|
||||
find(".d-modal:visible").length === 0,
|
||||
"modal should disappear when you click outside"
|
||||
);
|
||||
assert.equal(controller.name, null);
|
||||
|
||||
await click(".login-button");
|
||||
assert.ok(find(".d-modal:visible").length === 1, "modal should reappear");
|
||||
@@ -33,7 +38,7 @@ QUnit.test("modal", async assert => {
|
||||
'{{#d-modal-body title="" class="" dismissable=false}}test{{/d-modal-body}}'
|
||||
);
|
||||
|
||||
Ember.run(() => showModal("not-dismissable", {}));
|
||||
run(() => showModal("not-dismissable", {}));
|
||||
|
||||
assert.ok(find(".d-modal:visible").length === 1, "modal should appear");
|
||||
|
||||
@@ -48,3 +53,38 @@ QUnit.test("modal", async assert => {
|
||||
"ESC should not close the modal"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Modal Keyboard Events", { loggedIn: true });
|
||||
|
||||
QUnit.test("modal-keyboard-events", async function(assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-status-update button");
|
||||
await keyEvent(".d-modal", "keydown", 13);
|
||||
|
||||
assert.ok(
|
||||
find("#modal-alert:visible").length === 1,
|
||||
"hitting Enter triggers modal action"
|
||||
);
|
||||
assert.ok(
|
||||
find(".d-modal:visible").length === 1,
|
||||
"hitting Enter does not dismiss modal due to alert error"
|
||||
);
|
||||
|
||||
await keyEvent("#main-outlet", "keydown", 27);
|
||||
assert.ok(
|
||||
find(".d-modal:visible").length === 0,
|
||||
"ESC should close the modal"
|
||||
);
|
||||
|
||||
await click(".topic-body button.reply");
|
||||
|
||||
await click(".d-editor-button-bar .btn.link");
|
||||
|
||||
await keyEvent(".d-modal", "keydown", 13);
|
||||
assert.ok(
|
||||
find(".d-modal:visible").length === 0,
|
||||
"modal should disappear on hitting Enter"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -13,6 +13,17 @@ QUnit.test("footer edit button", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("suggested messages", async assert => {
|
||||
await visit("/t/pm-for-testing/12");
|
||||
|
||||
assert.equal(
|
||||
find("#suggested-topics .suggested-topics-title")
|
||||
.text()
|
||||
.trim(),
|
||||
I18n.t("suggested_topics.pm_title")
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Personal Message Tagging", {
|
||||
loggedIn: true,
|
||||
site: { can_tag_pms: true }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { extraConnectorClass } from "discourse/lib/plugin-connectors";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
const PREFIX = "javascripts/single-test/connectors";
|
||||
acceptance("Plugin Outlet - Connector Class", {
|
||||
@@ -12,6 +13,26 @@ acceptance("Plugin Outlet - Connector Class", {
|
||||
}
|
||||
});
|
||||
|
||||
extraConnectorClass("user-profile-primary/hi", {
|
||||
setupComponent() {
|
||||
this.appEvents.on("hi:sayHi", this, this.say);
|
||||
},
|
||||
|
||||
teardownComponent() {
|
||||
this.appEvents.off("hi:sayHi", this, this.say);
|
||||
},
|
||||
|
||||
@action
|
||||
say() {
|
||||
this.set("hi", "hi!");
|
||||
},
|
||||
|
||||
@action
|
||||
sayHi() {
|
||||
this.appEvents.trigger("hi:sayHi");
|
||||
}
|
||||
});
|
||||
|
||||
extraConnectorClass("user-profile-primary/dont-render", {
|
||||
shouldRender(args) {
|
||||
return args.model.get("username") !== "eviltrout";
|
||||
@@ -25,6 +46,12 @@ acceptance("Plugin Outlet - Connector Class", {
|
||||
<button class='say-hello' {{action "sayHello"}}></button>
|
||||
<span class='hello-result'>{{hello}}</span>`
|
||||
);
|
||||
Ember.TEMPLATES[
|
||||
`${PREFIX}/user-profile-primary/hi`
|
||||
] = Ember.HTMLBars.compile(
|
||||
`<button class='say-hi' {{action "sayHi"}}></button>
|
||||
<span class='hi-result'>{{hi}}</span>`
|
||||
);
|
||||
Ember.TEMPLATES[
|
||||
`${PREFIX}/user-profile-primary/dont-render`
|
||||
] = Ember.HTMLBars.compile(`I'm not rendered!`);
|
||||
@@ -32,6 +59,7 @@ acceptance("Plugin Outlet - Connector Class", {
|
||||
|
||||
afterEach() {
|
||||
delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hello`];
|
||||
delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hi`];
|
||||
delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/dont-render`];
|
||||
}
|
||||
});
|
||||
@@ -53,4 +81,7 @@ QUnit.test("Renders a template into the outlet", async assert => {
|
||||
"hello!",
|
||||
"actions delegate properly"
|
||||
);
|
||||
|
||||
await click(".say-hi");
|
||||
assert.equal(find(".hi-result").text(), "hi!", "actions delegate properly");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
|
||||
const PREFIX = "javascripts/single-test/connectors";
|
||||
acceptance("Plugin Outlet - Decorator", {
|
||||
loggedIn: true,
|
||||
|
||||
beforeEach() {
|
||||
Ember.TEMPLATES[
|
||||
`${PREFIX}/discovery-list-container-top/foo`
|
||||
] = Ember.HTMLBars.compile("FOO");
|
||||
Ember.TEMPLATES[
|
||||
`${PREFIX}/discovery-list-container-top/bar`
|
||||
] = Ember.HTMLBars.compile("BAR");
|
||||
|
||||
withPluginApi("0.8.38", api => {
|
||||
api.decoratePluginOutlet(
|
||||
"discovery-list-container-top",
|
||||
(elem, args) => {
|
||||
if (elem.classList.contains("foo")) {
|
||||
elem.style.backgroundColor = "yellow";
|
||||
|
||||
if (args.category) {
|
||||
elem.classList.add("in-category");
|
||||
} else {
|
||||
elem.classList.remove("in-category");
|
||||
}
|
||||
}
|
||||
},
|
||||
{ id: "yellow-decorator" }
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
delete Ember.TEMPLATES[`${PREFIX}/discovery-list-container-top/foo`];
|
||||
delete Ember.TEMPLATES[`${PREFIX}/discovery-list-container-top/bar`];
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Calls the plugin callback with the rendered outlet",
|
||||
async assert => {
|
||||
await visit("/");
|
||||
|
||||
const fooConnector = find(".discovery-list-container-top-outlet.foo ")[0];
|
||||
const barConnector = find(".discovery-list-container-top-outlet.bar ")[0];
|
||||
|
||||
assert.ok(exists(fooConnector));
|
||||
assert.equal(fooConnector.style.backgroundColor, "yellow");
|
||||
assert.equal(barConnector.style.backgroundColor, "");
|
||||
|
||||
await visit("/c/bug");
|
||||
|
||||
assert.ok(fooConnector.classList.contains("in-category"));
|
||||
|
||||
await visit("/");
|
||||
|
||||
assert.notOk(fooConnector.classList.contains("in-category"));
|
||||
}
|
||||
);
|
||||
@@ -1,18 +1,26 @@
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
|
||||
import User from "discourse/models/user";
|
||||
|
||||
acceptance("User Preferences", {
|
||||
loggedIn: true,
|
||||
pretend(server, helper) {
|
||||
server.post("/u/second_factors.json", () => {
|
||||
return helper.response({
|
||||
success: "OK",
|
||||
password_required: "true"
|
||||
});
|
||||
});
|
||||
|
||||
server.post("/u/create_second_factor_totp.json", () => {
|
||||
return helper.response({
|
||||
key: "rcyryaqage3jexfj",
|
||||
qr: '<div id="test-qr">qr-code</div>'
|
||||
});
|
||||
});
|
||||
|
||||
server.put("/u/second_factor.json", () => {
|
||||
server.post("/u/enable_second_factor_totp.json", () => {
|
||||
return helper.response({ error: "invalid token" });
|
||||
});
|
||||
|
||||
@@ -152,11 +160,6 @@ QUnit.test("username", async assert => {
|
||||
assert.ok(exists("#change_username"), "it has the input element");
|
||||
});
|
||||
|
||||
QUnit.test("about me", async assert => {
|
||||
await visit("/u/eviltrout/preferences/about-me");
|
||||
assert.ok(exists(".raw-bio"), "it has the input element");
|
||||
});
|
||||
|
||||
QUnit.test("email", async assert => {
|
||||
await visit("/u/eviltrout/preferences/email");
|
||||
|
||||
@@ -215,12 +218,13 @@ QUnit.test("second factor", async assert => {
|
||||
|
||||
await fillIn("#password", "secrets");
|
||||
await click(".user-preferences .btn-primary");
|
||||
|
||||
assert.ok(exists("#test-qr"), "shows qr code");
|
||||
assert.notOk(exists("#password"), "it hides the password input");
|
||||
|
||||
await click(".new-totp");
|
||||
assert.ok(exists("#test-qr"), "shows qr code");
|
||||
|
||||
await fillIn("#second-factor-token", "111111");
|
||||
await click(".btn-primary");
|
||||
await click(".add-totp");
|
||||
|
||||
assert.ok(
|
||||
find(".alert-error")
|
||||
@@ -230,20 +234,6 @@ QUnit.test("second factor", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("second factor backup", async assert => {
|
||||
await visit("/u/eviltrout/preferences/second-factor-backup");
|
||||
|
||||
assert.ok(
|
||||
exists("#second-factor-token"),
|
||||
"it has a authentication token input"
|
||||
);
|
||||
|
||||
await fillIn("#second-factor-token", "111111");
|
||||
await click(".user-preferences .btn-primary");
|
||||
|
||||
assert.ok(exists(".backup-codes-area"), "shows backup codes");
|
||||
});
|
||||
|
||||
QUnit.test("default avatar selector", async assert => {
|
||||
await visit("/u/eviltrout/preferences");
|
||||
|
||||
@@ -259,6 +249,40 @@ QUnit.test("default avatar selector", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Second Factor Backups", {
|
||||
loggedIn: true,
|
||||
pretend(server, helper) {
|
||||
server.post("/u/second_factors.json", () => {
|
||||
return helper.response({
|
||||
success: "OK",
|
||||
totps: [{ id: 1, name: "one of them" }]
|
||||
});
|
||||
});
|
||||
|
||||
server.put("/u/second_factors_backup.json", () => {
|
||||
return helper.response({
|
||||
backup_codes: ["dsffdsd", "fdfdfdsf", "fddsds"]
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/u/eviltrout/activity.json", () => {
|
||||
return helper.response({});
|
||||
});
|
||||
}
|
||||
});
|
||||
QUnit.test("second factor backup", async assert => {
|
||||
updateCurrentUser({ second_factor_enabled: true });
|
||||
await visit("/u/eviltrout/preferences/second-factor");
|
||||
await click(".edit-2fa-backup");
|
||||
assert.ok(
|
||||
exists(".second-factor-backup-preferences"),
|
||||
"shows the 2fa backup panel"
|
||||
);
|
||||
await click(".second-factor-backup-preferences .btn-primary");
|
||||
|
||||
assert.ok(exists(".backup-codes-area"), "shows backup codes");
|
||||
});
|
||||
|
||||
acceptance("Avatar selector when selectable avatars is enabled", {
|
||||
loggedIn: true,
|
||||
settings: { selectable_avatars_enabled: true },
|
||||
@@ -339,3 +363,82 @@ QUnit.test("recently connected devices", async assert => {
|
||||
"it should highlight password preferences"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"User can select a topic to feature on profile if site setting in enabled",
|
||||
{
|
||||
loggedIn: true,
|
||||
settings: { allow_featured_topic_on_user_profiles: true },
|
||||
|
||||
pretend(server, helper) {
|
||||
server.put("/u/eviltrout/feature-topic", () => {
|
||||
return helper.response({
|
||||
success: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("setting featured topic on profile", async assert => {
|
||||
await visit("/u/eviltrout/preferences/profile");
|
||||
|
||||
assert.ok(
|
||||
!exists(".featured-topic-link"),
|
||||
"no featured topic link to present"
|
||||
);
|
||||
assert.ok(
|
||||
!exists(".clear-feature-topic-on-profile-btn"),
|
||||
"clear button not present"
|
||||
);
|
||||
|
||||
const selectTopicBtn = find(".feature-topic-on-profile-btn:first");
|
||||
assert.ok(exists(selectTopicBtn), "feature topic button is present");
|
||||
|
||||
await click(selectTopicBtn);
|
||||
|
||||
assert.ok(exists(".feature-topic-on-profile"), "topic picker modal is open");
|
||||
|
||||
const topicRadioBtn = find('input[name="choose_topic_id"]:first');
|
||||
assert.ok(exists(topicRadioBtn), "Topic options are prefilled");
|
||||
await click(topicRadioBtn);
|
||||
|
||||
await click(".save-featured-topic-on-profile");
|
||||
|
||||
assert.ok(
|
||||
exists(".featured-topic-link"),
|
||||
"link to featured topic is present"
|
||||
);
|
||||
assert.ok(
|
||||
exists(".clear-feature-topic-on-profile-btn"),
|
||||
"clear button is present"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Custom User Fields", {
|
||||
loggedIn: true,
|
||||
site: {
|
||||
user_fields: [
|
||||
{
|
||||
id: 30,
|
||||
name: "What kind of pet do you have?",
|
||||
field_type: "dropdown",
|
||||
options: ["Dog", "Cat", "Hamster"],
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("can select an option from a dropdown", async assert => {
|
||||
await visit("/u/eviltrout/preferences/profile");
|
||||
assert.ok(exists(".user-field"), "it has at least one user field");
|
||||
await click(".user-field.dropdown");
|
||||
|
||||
const field = selectKit(
|
||||
".user-field-what-kind-of-pet-do-you-have .combo-box"
|
||||
);
|
||||
await field.expand();
|
||||
await field.selectRowByValue("Cat");
|
||||
assert.equal(field.header().value(), "Cat", "it sets the value of the field");
|
||||
});
|
||||
|
||||
@@ -27,3 +27,9 @@ QUnit.test("Visit reports page", async assert => {
|
||||
"List of my activities"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Visit report page", async assert => {
|
||||
await visit("/admin/reports/staff_logins");
|
||||
|
||||
assert.ok(exists(".export-csv-btn"));
|
||||
});
|
||||
|
||||
@@ -39,8 +39,11 @@ QUnit.test("Settings", async assert => {
|
||||
|
||||
assert.ok(find(".reviewable-score-type").length, "has a list of bonuses");
|
||||
|
||||
await fillIn(".reviewable-score-type:eq(0) .field input ", "0.5");
|
||||
const field = selectKit(".reviewable-score-type:eq(0) .field .combo-box");
|
||||
await field.expand();
|
||||
await field.selectRowByValue("5");
|
||||
await click(".save-settings");
|
||||
|
||||
assert.ok(find(".reviewable-settings .saved").length, "it saved");
|
||||
});
|
||||
|
||||
@@ -124,7 +127,7 @@ QUnit.test("Editing a reviewable", async assert => {
|
||||
let tags = selectKit(`${topic} .payload-tags .mini-tag-chooser`);
|
||||
await tags.expand();
|
||||
await tags.fillInFilter("monkey");
|
||||
await tags.keyboard("enter");
|
||||
await tags.selectRowByValue("monkey");
|
||||
|
||||
await fillIn(".editable-field.payload-raw textarea", "new raw contents");
|
||||
await click(`${topic} .reviewable-action.save-edit`);
|
||||
|
||||
@@ -278,7 +278,7 @@ QUnit.test(
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"update in:private filter through advanced search ui",
|
||||
"update in:personal filter through advanced search ui",
|
||||
async assert => {
|
||||
await visit("/search");
|
||||
await fillIn(".search-query", "none");
|
||||
@@ -290,8 +290,8 @@ QUnit.test(
|
||||
);
|
||||
assert.equal(
|
||||
find(".search-query").val(),
|
||||
"none in:private",
|
||||
'has updated search term to "none in:private"'
|
||||
"none in:personal",
|
||||
'has updated search term to "none in:personal"'
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -322,8 +322,9 @@ QUnit.test("update in filter through advanced search ui", async assert => {
|
||||
await inSelector.expand();
|
||||
await inSelector.selectRowByValue("bookmarks");
|
||||
|
||||
assert.ok(
|
||||
inSelector.rowByName("I bookmarked").exists(),
|
||||
assert.equal(
|
||||
inSelector.header().label(),
|
||||
"I bookmarked",
|
||||
'has "I bookmarked" populated'
|
||||
);
|
||||
assert.equal(
|
||||
@@ -344,8 +345,9 @@ QUnit.test("update status through advanced search ui", async assert => {
|
||||
await statusSelector.expand();
|
||||
await statusSelector.selectRowByValue("closed");
|
||||
|
||||
assert.ok(
|
||||
statusSelector.rowByName("are closed").exists(),
|
||||
assert.equal(
|
||||
statusSelector.header().label(),
|
||||
"are closed",
|
||||
'has "are closed" populated'
|
||||
);
|
||||
assert.equal(
|
||||
@@ -364,19 +366,20 @@ QUnit.test("update post time through advanced search ui", async assert => {
|
||||
"it should update the search term correctly"
|
||||
);
|
||||
|
||||
const postTimeSelector = selectKit(
|
||||
".search-advanced-options .select-kit#postTime"
|
||||
);
|
||||
|
||||
await visit("/search");
|
||||
|
||||
await fillIn(".search-query", "none");
|
||||
await fillIn("#search-post-date .date-picker", "2016-10-05");
|
||||
await fillIn("#search-post-date .date-picker", "October 5, 2016");
|
||||
|
||||
const postTimeSelector = selectKit(
|
||||
".search-advanced-options .select-kit#postTime"
|
||||
);
|
||||
await postTimeSelector.expand();
|
||||
await postTimeSelector.selectRowByValue("after");
|
||||
|
||||
assert.ok(
|
||||
postTimeSelector.rowByName("after").exists(),
|
||||
assert.equal(
|
||||
postTimeSelector.header().label(),
|
||||
"after",
|
||||
'has "after" populated'
|
||||
);
|
||||
|
||||
@@ -409,7 +412,7 @@ QUnit.test("validate advanced search when initially empty", async assert => {
|
||||
await click(".search-advanced-options .in-likes");
|
||||
|
||||
assert.ok(
|
||||
exists(".search-advanced-options .in-likes:checked"),
|
||||
selectKit(".search-advanced-options .in-likes:checked"),
|
||||
'has "I liked" populated'
|
||||
);
|
||||
assert.equal(
|
||||
|
||||
@@ -50,6 +50,14 @@ QUnit.test("search for a tag", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("search scope checkbox", async assert => {
|
||||
await visit("/tag/important");
|
||||
await click("#search-button");
|
||||
assert.ok(
|
||||
exists(".search-context input:checked"),
|
||||
"scope to tag checkbox is checked"
|
||||
);
|
||||
await click("#search-button");
|
||||
|
||||
await visit("/c/bug");
|
||||
await click("#search-button");
|
||||
assert.ok(
|
||||
@@ -163,3 +171,27 @@ QUnit.test("Right filters are shown to logged-in users", async assert => {
|
||||
assert.ok(exists(".search-advanced-options .in-private"));
|
||||
assert.ok(exists(".search-advanced-options .in-seen"));
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"Search - with tagging enabled",
|
||||
Object.assign({
|
||||
loggedIn: true,
|
||||
searchArgs,
|
||||
settings: { tagging_enabled: true }
|
||||
})
|
||||
);
|
||||
|
||||
QUnit.test("displays tags", async assert => {
|
||||
await visit("/");
|
||||
|
||||
await click("#search-button");
|
||||
|
||||
await fillIn("#search-term", "dev");
|
||||
await keyEvent("#search-term", "keyup", 16);
|
||||
|
||||
const tags = find(".search-menu .results ul li:eq(0) .discourse-tags")
|
||||
.text()
|
||||
.trim();
|
||||
|
||||
assert.equal(tags, "dev slow");
|
||||
});
|
||||
|
||||
@@ -101,6 +101,32 @@ QUnit.test("second factor", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("security key", async assert => {
|
||||
await visit("/");
|
||||
await click("header .login-button");
|
||||
|
||||
assert.ok(exists(".login-modal"), "it shows the login modal");
|
||||
|
||||
await fillIn("#login-account-name", "eviltrout");
|
||||
await fillIn("#login-account-password", "need-security-key");
|
||||
await click(".modal-footer .btn-primary");
|
||||
|
||||
assert.not(exists("#modal-alert:visible"), "it hides the login error");
|
||||
assert.not(
|
||||
exists("#credentials:visible"),
|
||||
"it hides the username and password prompt"
|
||||
);
|
||||
assert.not(
|
||||
exists("#login-second-factor:visible"),
|
||||
"it does not display the second factor prompt"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#security-key:visible"),
|
||||
"it shows the security key prompt"
|
||||
);
|
||||
assert.not(exists("#login-button:visible"), "hides the login button");
|
||||
});
|
||||
|
||||
QUnit.test("create account", async assert => {
|
||||
await visit("/");
|
||||
await click("header .sign-up-button");
|
||||
|
||||
@@ -6,7 +6,7 @@ acceptance("Tag Hashtag", {
|
||||
pretend(server, helper) {
|
||||
server.get("/tags/check", () => {
|
||||
return helper.response({
|
||||
valid: [{ value: "monkey", url: "/tags/monkey" }]
|
||||
valid: [{ value: "monkey", url: "/tag/monkey" }]
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -22,14 +22,6 @@ QUnit.test("tag is cooked properly", async assert => {
|
||||
find(".d-editor-preview:visible")
|
||||
.html()
|
||||
.trim(),
|
||||
'<p>this is a tag hashtag <a href="/tags/monkey" class="hashtag">#<span>monkey</span></a></p>'
|
||||
);
|
||||
|
||||
await click("#reply-control .btn.create");
|
||||
assert.equal(
|
||||
find(".topic-post:last .cooked")
|
||||
.html()
|
||||
.trim(),
|
||||
'<p>this is a tag hashtag <a href="/tags/monkey" class="hashtag">#<span>monkey</span></a></p>'
|
||||
'<p>this is a tag hashtag <a href="/tag/monkey" class="hashtag">#<span>monkey</span></a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ acceptance("Tags intersection", {
|
||||
site: { can_tag_topics: true },
|
||||
settings: { tagging_enabled: true },
|
||||
pretend(server, helper) {
|
||||
server.get("/tags/first/notifications", () => {
|
||||
server.get("/tag/first/notifications", () => {
|
||||
return helper.response({
|
||||
tag_notification: { id: "first", notification_level: 1 }
|
||||
});
|
||||
|
||||
@@ -25,7 +25,10 @@ QUnit.test("list the tags in groups", async assert => {
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{
|
||||
tags: [{ id: "planned", text: "planned", count: 7, pm_count: 0 }],
|
||||
tags: [
|
||||
{ id: "planned", text: "planned", count: 7, pm_count: 0 },
|
||||
{ id: "private", text: "private", count: 0, pm_count: 7 }
|
||||
],
|
||||
extras: {
|
||||
tag_groups: [
|
||||
{
|
||||
@@ -88,20 +91,25 @@ QUnit.test("list the tags in groups", async assert => {
|
||||
.map(i => {
|
||||
return $(i).attr("href");
|
||||
}),
|
||||
["/tags/focus", "/tags/escort"],
|
||||
["/tag/focus", "/tag/escort"],
|
||||
"always uses lowercase URLs for mixed case tags"
|
||||
);
|
||||
assert.equal(
|
||||
$("a[data-tag-name='private']").attr("href"),
|
||||
"/u/eviltrout/messages/tags/private",
|
||||
"links to private messages"
|
||||
);
|
||||
});
|
||||
|
||||
test("new topic button is not available for staff-only tags", async assert => {
|
||||
/* global server */
|
||||
server.get("/tags/regular-tag/notifications", () => [
|
||||
server.get("/tag/regular-tag/notifications", () => [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{ tag_notification: { id: "regular-tag", notification_level: 1 } }
|
||||
]);
|
||||
|
||||
server.get("/tags/regular-tag/l/latest.json", () => [
|
||||
server.get("/tag/regular-tag/l/latest.json", () => [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{
|
||||
@@ -125,13 +133,13 @@ test("new topic button is not available for staff-only tags", async assert => {
|
||||
}
|
||||
]);
|
||||
|
||||
server.get("/tags/staff-only-tag/notifications", () => [
|
||||
server.get("/tag/staff-only-tag/notifications", () => [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{ tag_notification: { id: "staff-only-tag", notification_level: 1 } }
|
||||
]);
|
||||
|
||||
server.get("/tags/staff-only-tag/l/latest.json", () => [
|
||||
server.get("/tag/staff-only-tag/l/latest.json", () => [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{
|
||||
@@ -156,19 +164,157 @@ test("new topic button is not available for staff-only tags", async assert => {
|
||||
}
|
||||
]);
|
||||
|
||||
updateCurrentUser({ staff: false });
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/tags/regular-tag");
|
||||
await visit("/tag/regular-tag");
|
||||
assert.ok(find("#create-topic:disabled").length === 0);
|
||||
|
||||
await visit("/tags/staff-only-tag");
|
||||
await visit("/tag/staff-only-tag");
|
||||
assert.ok(find("#create-topic:disabled").length === 1);
|
||||
|
||||
updateCurrentUser({ staff: true });
|
||||
updateCurrentUser({ moderator: true });
|
||||
|
||||
await visit("/tags/regular-tag");
|
||||
await visit("/tag/regular-tag");
|
||||
assert.ok(find("#create-topic:disabled").length === 0);
|
||||
|
||||
await visit("/tags/staff-only-tag");
|
||||
await visit("/tag/staff-only-tag");
|
||||
assert.ok(find("#create-topic:disabled").length === 0);
|
||||
});
|
||||
|
||||
acceptance("Tag info", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
tags_listed_by_group: true
|
||||
},
|
||||
pretend(server, helper) {
|
||||
server.get("/tag/planters/notifications", () => {
|
||||
return helper.response({
|
||||
tag_notification: { id: "planters", notification_level: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/tag/planters/l/latest.json", () => {
|
||||
return helper.response({
|
||||
users: [],
|
||||
primary_groups: [],
|
||||
topic_list: {
|
||||
can_create_topic: true,
|
||||
draft: null,
|
||||
draft_key: "new_topic",
|
||||
draft_sequence: 1,
|
||||
per_page: 30,
|
||||
tags: [
|
||||
{
|
||||
id: 1,
|
||||
name: "planters",
|
||||
topic_count: 1
|
||||
}
|
||||
],
|
||||
topics: []
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/tag/planters/info", () => {
|
||||
return helper.response({
|
||||
__rest_serializer: "1",
|
||||
tag_info: {
|
||||
id: 12,
|
||||
name: "planters",
|
||||
topic_count: 1,
|
||||
staff: false,
|
||||
synonyms: [
|
||||
{
|
||||
id: "containers",
|
||||
text: "containers"
|
||||
},
|
||||
{
|
||||
id: "planter",
|
||||
text: "planter"
|
||||
}
|
||||
],
|
||||
tag_group_names: ["Gardening"],
|
||||
category_ids: [7]
|
||||
},
|
||||
categories: [
|
||||
{
|
||||
id: 7,
|
||||
name: "Outdoors",
|
||||
color: "000",
|
||||
text_color: "FFFFFF",
|
||||
slug: "outdoors",
|
||||
topic_count: 701,
|
||||
post_count: 5320,
|
||||
description: "Talk about the outdoors.",
|
||||
description_text: "Talk about the outdoors.",
|
||||
topic_url: "/t/category-definition-for-outdoors/1026",
|
||||
read_restricted: false,
|
||||
permission: null,
|
||||
notification_level: null
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test("tag info can show synonyms", async assert => {
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/tag/planters");
|
||||
assert.ok(find("#show-tag-info").length === 1);
|
||||
|
||||
await click("#show-tag-info");
|
||||
assert.ok(exists(".tag-info .tag-name"), "show tag");
|
||||
assert.ok(
|
||||
find(".tag-info .tag-associations")
|
||||
.text()
|
||||
.indexOf("Gardening") >= 0,
|
||||
"show tag group names"
|
||||
);
|
||||
assert.ok(
|
||||
find(".tag-info .synonyms-list .tag-box").length === 2,
|
||||
"shows the synonyms"
|
||||
);
|
||||
assert.ok(
|
||||
find(".tag-info .badge-category").length === 1,
|
||||
"show the category"
|
||||
);
|
||||
assert.ok(!exists("#rename-tag"), "can't rename tag");
|
||||
assert.ok(!exists("#edit-synonyms"), "can't edit synonyms");
|
||||
assert.ok(!exists("#delete-tag"), "can't delete tag");
|
||||
});
|
||||
|
||||
test("admin can manage tags", async assert => {
|
||||
server.delete("/tag/planters/synonyms/containers", () => [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{ success: true }
|
||||
]);
|
||||
|
||||
updateCurrentUser({ moderator: false, admin: true });
|
||||
|
||||
await visit("/tag/planters");
|
||||
assert.ok(find("#show-tag-info").length === 1);
|
||||
|
||||
await click("#show-tag-info");
|
||||
assert.ok(exists("#rename-tag"), "can rename tag");
|
||||
assert.ok(exists("#edit-synonyms"), "can edit synonyms");
|
||||
assert.ok(exists("#delete-tag"), "can delete tag");
|
||||
|
||||
await click("#edit-synonyms");
|
||||
assert.ok(
|
||||
find(".unlink-synonym:visible").length === 2,
|
||||
"unlink UI is visible"
|
||||
);
|
||||
assert.ok(
|
||||
find(".delete-synonym:visible").length === 2,
|
||||
"delete UI is visible"
|
||||
);
|
||||
|
||||
await click(".unlink-synonym:first");
|
||||
assert.ok(
|
||||
find(".tag-info .synonyms-list .tag-box").length === 1,
|
||||
"removed a synonym"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -19,10 +19,7 @@ QUnit.test("Enter without an id", async assert => {
|
||||
QUnit.test("Enter a 404 topic", async assert => {
|
||||
await visit("/t/not-found/404");
|
||||
assert.ok(!exists("#topic"), "The topic was not rendered");
|
||||
assert.ok(
|
||||
find(".not-found").text() === "not found",
|
||||
"it renders the error message"
|
||||
);
|
||||
assert.ok(exists(".topic-error"), "An error message is displayed");
|
||||
});
|
||||
|
||||
QUnit.test("Enter without access", async assert => {
|
||||
|
||||
@@ -76,3 +76,32 @@ QUnit.test("Clearing state after leaving a category", async assert => {
|
||||
"it doesn't expand all pinned in the latest category"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Live update unread state", async assert => {
|
||||
await visit("/");
|
||||
assert.ok(
|
||||
exists(".topic-list-item:not(.visited) a[data-topic-id='11995']"),
|
||||
"shows the topic unread"
|
||||
);
|
||||
|
||||
// Mimic a messagebus message
|
||||
window.MessageBus.callbacks.filterBy("channel", "/latest").map(c =>
|
||||
c.func({
|
||||
message_type: "read",
|
||||
topic_id: 11995,
|
||||
payload: {
|
||||
highest_post_number: 1,
|
||||
last_read_post_number: 2,
|
||||
notification_level: 1,
|
||||
topic_id: 11995
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
await visit("/"); // We're already there, but use this to wait for re-render
|
||||
|
||||
assert.ok(
|
||||
exists(".topic-list-item.visited a[data-topic-id='11995']"),
|
||||
"shows the topic read"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ acceptance("Topic - Edit timer", {
|
||||
});
|
||||
|
||||
QUnit.test("default", async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const timerType = selectKit(".select-kit.timer-type");
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
@@ -28,20 +28,20 @@ QUnit.test("default", async assert => {
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-status-update button");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().label(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().value(), null);
|
||||
|
||||
await click("#private-topic-timer");
|
||||
|
||||
assert.equal(timerType.header().title(), "Remind Me");
|
||||
assert.equal(timerType.header().label(), "Remind Me");
|
||||
assert.equal(timerType.header().value(), "reminder");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().label(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().value(), null);
|
||||
});
|
||||
|
||||
QUnit.test("autoclose - specific time", async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
await visit("/t/internationalization-localization");
|
||||
@@ -51,7 +51,12 @@ QUnit.test("autoclose - specific time", async assert => {
|
||||
await futureDateInputSelector.expand();
|
||||
await futureDateInputSelector.selectRowByValue("next_week");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Next week");
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Next week")
|
||||
);
|
||||
assert.equal(futureDateInputSelector.header().value(), "next_week");
|
||||
|
||||
const regex = /will automatically close in/g;
|
||||
@@ -62,7 +67,7 @@ QUnit.test("autoclose - specific time", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("autoclose", async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
await visit("/t/internationalization-localization");
|
||||
@@ -72,7 +77,12 @@ QUnit.test("autoclose", async assert => {
|
||||
await futureDateInputSelector.expand();
|
||||
await futureDateInputSelector.selectRowByValue("next_week");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Next week");
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Next week")
|
||||
);
|
||||
assert.equal(futureDateInputSelector.header().value(), "next_week");
|
||||
|
||||
const regex1 = /will automatically close in/g;
|
||||
@@ -86,7 +96,12 @@ QUnit.test("autoclose", async assert => {
|
||||
|
||||
await fillIn(".future-date-input .date-picker", "2099-11-24");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Pick date and time");
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Pick date and time")
|
||||
);
|
||||
assert.equal(futureDateInputSelector.header().value(), "pick_date_and_time");
|
||||
|
||||
const regex2 = /will automatically close in/g;
|
||||
@@ -100,9 +115,11 @@ QUnit.test("autoclose", async assert => {
|
||||
|
||||
await fillIn(".future-date-input input[type=number]", "2");
|
||||
|
||||
assert.equal(
|
||||
futureDateInputSelector.header().title(),
|
||||
"Close based on last post"
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Close based on last post")
|
||||
);
|
||||
assert.equal(
|
||||
futureDateInputSelector.header().value(),
|
||||
@@ -117,7 +134,7 @@ QUnit.test("autoclose", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("close temporarily", async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const timerType = selectKit(".select-kit.timer-type");
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
@@ -128,13 +145,18 @@ QUnit.test("close temporarily", async assert => {
|
||||
await timerType.expand();
|
||||
await timerType.selectRowByValue("open");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().label(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().value(), null);
|
||||
|
||||
await futureDateInputSelector.expand();
|
||||
await futureDateInputSelector.selectRowByValue("next_week");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Next week");
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Next week")
|
||||
);
|
||||
assert.equal(futureDateInputSelector.header().value(), "next_week");
|
||||
|
||||
const regex1 = /will automatically open in/g;
|
||||
@@ -148,7 +170,7 @@ QUnit.test("close temporarily", async assert => {
|
||||
|
||||
await fillIn(".future-date-input .date-picker", "2099-11-24");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Pick date and time");
|
||||
assert.equal(futureDateInputSelector.header().label(), "Pick date and time");
|
||||
assert.equal(futureDateInputSelector.header().value(), "pick_date_and_time");
|
||||
|
||||
const regex2 = /will automatically open in/g;
|
||||
@@ -159,7 +181,7 @@ QUnit.test("close temporarily", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("schedule", async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const timerType = selectKit(".select-kit.timer-type");
|
||||
const categoryChooser = selectKit(".modal-body .category-chooser");
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
@@ -171,10 +193,10 @@ QUnit.test("schedule", async assert => {
|
||||
await timerType.expand();
|
||||
await timerType.selectRowByValue("publish_to_category");
|
||||
|
||||
assert.equal(categoryChooser.header().title(), "uncategorized");
|
||||
assert.equal(categoryChooser.header().label(), "uncategorized");
|
||||
assert.equal(categoryChooser.header().value(), null);
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().label(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().value(), null);
|
||||
|
||||
await categoryChooser.expand();
|
||||
@@ -183,7 +205,12 @@ QUnit.test("schedule", async assert => {
|
||||
await futureDateInputSelector.expand();
|
||||
await futureDateInputSelector.selectRowByValue("next_week");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Next week");
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Next week")
|
||||
);
|
||||
assert.equal(futureDateInputSelector.header().value(), "next_week");
|
||||
|
||||
const regex = /will be published to #dev/g;
|
||||
@@ -194,7 +221,7 @@ QUnit.test("schedule", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("TL4 can't auto-delete", async assert => {
|
||||
updateCurrentUser({ staff: false, trust_level: 4 });
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 4 });
|
||||
|
||||
await visit("/t/internationalization-localization");
|
||||
await click(".toggle-admin-menu");
|
||||
@@ -208,7 +235,7 @@ QUnit.test("TL4 can't auto-delete", async assert => {
|
||||
});
|
||||
|
||||
QUnit.test("auto delete", async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const timerType = selectKit(".select-kit.timer-type");
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
@@ -219,13 +246,18 @@ QUnit.test("auto delete", async assert => {
|
||||
await timerType.expand();
|
||||
await timerType.selectRowByValue("delete");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().label(), "Select a timeframe");
|
||||
assert.equal(futureDateInputSelector.header().value(), null);
|
||||
|
||||
await futureDateInputSelector.expand();
|
||||
await futureDateInputSelector.selectRowByValue("two_weeks");
|
||||
|
||||
assert.equal(futureDateInputSelector.header().title(), "Two Weeks");
|
||||
assert.ok(
|
||||
futureDateInputSelector
|
||||
.header()
|
||||
.label()
|
||||
.includes("Two Weeks")
|
||||
);
|
||||
assert.equal(futureDateInputSelector.header().value(), "two_weeks");
|
||||
|
||||
const regex = /will be automatically deleted/g;
|
||||
@@ -238,7 +270,7 @@ QUnit.test("auto delete", async assert => {
|
||||
QUnit.test(
|
||||
"Manually closing before the timer will clear the status text",
|
||||
async assert => {
|
||||
updateCurrentUser({ admin: true, staff: true, canManageTopic: true });
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
await visit("/t/internationalization-localization");
|
||||
@@ -263,3 +295,22 @@ QUnit.test(
|
||||
assert.notOk(regex.test(newTopicStatusInfo));
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("Inline delete timer", async assert => {
|
||||
updateCurrentUser({ moderator: true, canManageTopic: true });
|
||||
const futureDateInputSelector = selectKit(".future-date-input-selector");
|
||||
|
||||
await visit("/t/internationalization-localization");
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-status-update button");
|
||||
await futureDateInputSelector.expand();
|
||||
await futureDateInputSelector.selectRowByValue("next_week");
|
||||
await click(".modal-footer button.btn-primary");
|
||||
|
||||
const removeTimerButton = find(".topic-status-info .topic-timer-remove");
|
||||
assert.equal(removeTimerButton.attr("title"), "remove timer");
|
||||
|
||||
await click(".topic-status-info .topic-timer-remove");
|
||||
const topicStatusInfo = find(".topic-status-info .topic-timer-remove");
|
||||
assert.equal(topicStatusInfo.length, 0);
|
||||
});
|
||||
|
||||
@@ -18,28 +18,28 @@ QUnit.test("default", async assert => {
|
||||
await click(".selected-posts .move-to-topic");
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .title")
|
||||
find(".choose-topic-modal .title")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to.title")),
|
||||
"it opens move to modal"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.split_topic.radio_label")),
|
||||
"it shows an option to move to new topic"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.merge_topic.radio_label")),
|
||||
"it shows an option to move to existing topic"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_new_message.radio_label")),
|
||||
"it shows an option to move to new message"
|
||||
@@ -54,28 +54,28 @@ QUnit.test("moving all posts", async assert => {
|
||||
await click(".selected-posts .move-to-topic");
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .title")
|
||||
find(".choose-topic-modal .title")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to.title")),
|
||||
"it opens move to modal"
|
||||
);
|
||||
|
||||
assert.not(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.split_topic.radio_label")),
|
||||
"it does not show an option to move to new topic"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.merge_topic.radio_label")),
|
||||
"it shows an option to move to existing topic"
|
||||
);
|
||||
|
||||
assert.not(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_new_message.radio_label")),
|
||||
"it does not show an option to move to new message"
|
||||
@@ -99,21 +99,21 @@ QUnit.test("moving posts from personal message", async assert => {
|
||||
await click(".selected-posts .move-to-topic");
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .title")
|
||||
find(".choose-topic-modal .title")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to.title")),
|
||||
"it opens move to modal"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_new_message.radio_label")),
|
||||
"it shows an option to move to new message"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
find(".choose-topic-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_existing_message.radio_label")),
|
||||
"it shows an option to move to existing message"
|
||||
|
||||
@@ -26,8 +26,33 @@ QUnit.test("Updating topic notification level", async assert => {
|
||||
await notificationOptions.selectRowByValue("3");
|
||||
|
||||
assert.equal(
|
||||
notificationOptions.selectedRow().name(),
|
||||
notificationOptions.header().label(),
|
||||
"Watching",
|
||||
"it should display the right notification level"
|
||||
);
|
||||
|
||||
const timelineNotificationOptions = selectKit(
|
||||
".topic-timeline .widget-component-connector .topic-notifications-options"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
timelineNotificationOptions.header().value(),
|
||||
"3",
|
||||
"it should display the right notification level"
|
||||
);
|
||||
|
||||
await timelineNotificationOptions.expand();
|
||||
await timelineNotificationOptions.selectRowByValue("0");
|
||||
|
||||
assert.equal(
|
||||
timelineNotificationOptions.header().value(),
|
||||
"0",
|
||||
"it should display the right notification level"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
notificationOptions.header().label(),
|
||||
"Muted",
|
||||
"it should display the right notification level"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -22,9 +22,7 @@ QUnit.test("Reply as new topic", async assert => {
|
||||
find(".d-editor-input")
|
||||
.val()
|
||||
.trim(),
|
||||
`Continuing the discussion from [Internationalization / localization](${
|
||||
window.location.origin
|
||||
}/t/internationalization-localization/280):`,
|
||||
`Continuing the discussion from [Internationalization / localization](${window.location.origin}/t/internationalization-localization/280):`,
|
||||
"it fills composer with the ring string"
|
||||
);
|
||||
assert.equal(
|
||||
@@ -47,9 +45,7 @@ QUnit.test("Reply as new message", async assert => {
|
||||
find(".d-editor-input")
|
||||
.val()
|
||||
.trim(),
|
||||
`Continuing the discussion from [PM for testing](${
|
||||
window.location.origin
|
||||
}/t/pm-for-testing/12):`,
|
||||
`Continuing the discussion from [PM for testing](${window.location.origin}/t/pm-for-testing/12):`,
|
||||
"it fills composer with the ring string"
|
||||
);
|
||||
|
||||
@@ -190,6 +186,46 @@ QUnit.test("Updating the topic title with unicode emojis", async assert => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Updating the topic title with unicode emojis without whitespaces",
|
||||
async assert => {
|
||||
Discourse.SiteSettings.enable_inline_emoji_translation = true;
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-title .d-icon-pencil-alt");
|
||||
|
||||
await fillIn("#edit-title", "Test🙂Title");
|
||||
|
||||
await click("#topic-title .submit-edit");
|
||||
|
||||
assert.equal(
|
||||
find(".fancy-title")
|
||||
.html()
|
||||
.trim(),
|
||||
`Test<img src="/images/emoji/emoji_one/slightly_smiling_face.png?v=${v}" title="slightly_smiling_face" alt="slightly_smiling_face" class="emoji">Title`,
|
||||
"it displays the new title with escaped unicode emojis"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("Suggested topics", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
assert.equal(
|
||||
find("#suggested-topics .suggested-topics-title")
|
||||
.text()
|
||||
.trim(),
|
||||
I18n.t("suggested_topics.title")
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("Deleting a topic", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:eq(0) button.show-more-actions");
|
||||
await click(".widget-button.delete");
|
||||
|
||||
assert.ok(exists(".widget-button.recover"), "it shows the recover button");
|
||||
});
|
||||
|
||||
acceptance("Topic featured links", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
@@ -199,7 +235,7 @@ acceptance("Topic featured links", {
|
||||
});
|
||||
|
||||
QUnit.test("remove featured link", async assert => {
|
||||
await visit("/t/299/1");
|
||||
await visit("/t/-/299/1");
|
||||
assert.ok(
|
||||
exists(".title-wrapper .topic-featured-link"),
|
||||
"link is shown with topic title"
|
||||
@@ -217,6 +253,20 @@ QUnit.test("remove featured link", async assert => {
|
||||
// assert.ok(!exists('.title-wrapper .topic-featured-link'), 'link is gone');
|
||||
});
|
||||
|
||||
QUnit.test("Converting to a public topic", async assert => {
|
||||
await visit("/t/test-pm/34");
|
||||
assert.ok(exists(".private_message"));
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-convert button");
|
||||
|
||||
let categoryChooser = selectKit(".convert-to-public-topic .category-chooser");
|
||||
await categoryChooser.expand();
|
||||
await categoryChooser.selectRowByValue(21);
|
||||
|
||||
await click(".convert-to-public-topic .btn-primary");
|
||||
assert.ok(!exists(".private_message"));
|
||||
});
|
||||
|
||||
QUnit.test("Unpinning unlisted topic", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
@@ -245,13 +295,6 @@ QUnit.test("selecting posts", async assert => {
|
||||
exists(".select-all"),
|
||||
"it should allow users to select all the posts"
|
||||
);
|
||||
|
||||
await click(".toggle-admin-menu");
|
||||
|
||||
assert.ok(
|
||||
exists(".selected-posts.hidden"),
|
||||
"it should hide the multi select menu"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("select below", async assert => {
|
||||
@@ -283,3 +326,35 @@ QUnit.test("View Hidden Replies", async assert => {
|
||||
|
||||
assert.equal(find(".gap").length, 0, "it hides gap");
|
||||
});
|
||||
|
||||
QUnit.test("Quoting a quote keeps the original poster name", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents($("#post_5 blockquote")[0]);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
await click(".quote-button");
|
||||
|
||||
assert.ok(
|
||||
find(".d-editor-input")
|
||||
.val()
|
||||
.indexOf('quote="codinghorror said, post:3, topic:280"') !== -1
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Topic + Post Bookmarks with Reminders", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
enable_bookmarks_with_reminders: true
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("Bookmarks Modal", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:first-child button.show-more-actions");
|
||||
await click(".topic-post:first-child button.bookmark");
|
||||
assert.ok(exists("#bookmark-reminder-modal"), "it shows the bookmark modal");
|
||||
});
|
||||
|
||||
@@ -6,12 +6,12 @@ acceptance("User Card - Mobile", { mobileView: true });
|
||||
QUnit.skip("user card", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
assert.ok(
|
||||
invisible("#user-card"),
|
||||
invisible(".user-card"),
|
||||
"mobile user card is invisible by default"
|
||||
);
|
||||
|
||||
await click("a[data-user-card=eviltrout]:first");
|
||||
assert.ok(visible("#user-card"), "mobile user card should appear");
|
||||
assert.ok(visible(".user-card"), "mobile user card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.user-profile-link");
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
|
||||
acceptance("User Card");
|
||||
acceptance("User Card", { loggedIn: true });
|
||||
|
||||
QUnit.test("user card", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
assert.ok(invisible("#user-card"), "user card is invisible by default");
|
||||
assert.ok(invisible(".user-card"), "user card is invisible by default");
|
||||
|
||||
await click("a[data-user-card=eviltrout]:first");
|
||||
assert.ok(visible("#user-card"), "card should appear");
|
||||
assert.ok(visible(".user-card"), "card should appear");
|
||||
assert.equal(
|
||||
find(".user-card .username")
|
||||
.text()
|
||||
.trim(),
|
||||
"eviltrout",
|
||||
"user card contains the data"
|
||||
);
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.user-profile-link");
|
||||
@@ -16,4 +23,34 @@ QUnit.test("user card", async assert => {
|
||||
DiscourseURL.routeTo.calledWith("/u/eviltrout"),
|
||||
"it should navigate to the user profile"
|
||||
);
|
||||
|
||||
await click("a[data-user-card=charlie]:first");
|
||||
assert.ok(visible(".user-card"), "card should appear");
|
||||
assert.equal(
|
||||
find(".user-card .username")
|
||||
.text()
|
||||
.trim(),
|
||||
"charlie",
|
||||
"user card contains the data"
|
||||
);
|
||||
|
||||
await click(".card-content .compose-pm button");
|
||||
assert.ok(
|
||||
invisible(".user-card"),
|
||||
"user card dismissed after hitting Message button"
|
||||
);
|
||||
|
||||
const mention = find("a.mention");
|
||||
const icon = document.createElement("span");
|
||||
icon.classList.add("icon");
|
||||
mention.append(icon);
|
||||
await click("a.mention .icon");
|
||||
assert.ok(visible(".user-card"), "card should appear");
|
||||
assert.equal(
|
||||
find(".user-card .username")
|
||||
.text()
|
||||
.trim(),
|
||||
"eviltrout",
|
||||
"user card contains the data"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -12,3 +12,16 @@ QUnit.test("Stream", async assert => {
|
||||
"draft removed, list length diminished by one"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Stream - resume draft", async assert => {
|
||||
await visit("/u/eviltrout/activity/drafts");
|
||||
assert.ok(find(".user-stream-item").length > 0, "has drafts");
|
||||
|
||||
await click(".user-stream-item .resume-draft");
|
||||
assert.equal(
|
||||
find(".d-editor-input")
|
||||
.val()
|
||||
.trim(),
|
||||
"A fun new topic for testing drafts."
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user