This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
Martin Brennan f6528afa01
DEV: Add uploadHandler support to composer-upload-uppy mixin (#14692)
This commit adds uploadHandler support to composer uploads using
uppy. The only things we have that are using this are discourse-brightcove and
discourse-video, which both pop modal windows to handle the file upload and
completely leave out all the composer-type flows. This implementation simply
follows the existing one, where if a single file is uploaded and there
is a matching upload handler we take control away from uppy and hand
it off to the upload handler.

Trying to get this kind of thing working within uppy would require a few
changes because they have no way to restrict uploaders to certain file types
and with the way their uploaders are run it doesn't look like it would be easy
to add this either, so I don't think this is worth the work unless at some
point in the future we plan to have more upload handler integrations.

I also fixed an issue with `cleanUpComposerUploadHandler` which is used
in tests to reset the state of `uploadHandlers` in the composer. This
was doing `uploadHandlers = []` to clear that array, but that creates
a brand new array so anything else referencing the original array will
lose that reference. Better to set `uploadHandlers.length = 0` to
clear it. This was breaking the tests I added to see if upload handlers
were working.
2021-10-26 11:22:33 +10:00

327 lines
11 KiB
JavaScript

import {
acceptance,
exists,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import { withPluginApi } from "discourse/lib/plugin-api";
import { click, fillIn, visit } from "@ember/test-helpers";
import bootbox from "bootbox";
import { test } from "qunit";
function pretender(server, helper) {
server.post("/uploads/lookup-urls", () => {
return helper.response([
{
short_url: "upload://asdsad.png",
url: "/secure-media-uploads/default/3X/1/asjdiasjdiasida.png",
short_path: "/uploads/short-url/asdsad.png",
},
]);
});
}
async function writeInComposer(assert) {
await visit("/t/internationalization-localization/280");
await click("#topic-footer-buttons .btn.create");
await fillIn(".d-editor-input", "[test](upload://abcdefg.png)");
assert.equal(
queryAll(".d-editor-preview:visible").html().trim(),
'<p><a href="/404" tabindex="-1">test</a></p>'
);
await fillIn(".d-editor-input", "[test|attachment](upload://asdsad.png)");
}
acceptance("Composer Attachment - Cooking", function (needs) {
needs.user();
needs.pretender(pretender);
test("attachments are cooked properly", async function (assert) {
await writeInComposer(assert);
assert.equal(
queryAll(".d-editor-preview:visible").html().trim(),
'<p><a class="attachment" href="/uploads/short-url/asdsad.png" tabindex="-1">test</a></p>'
);
});
});
acceptance("Composer Attachment - Secure Media Enabled", function (needs) {
needs.user();
needs.settings({ secure_media: true });
needs.pretender(pretender);
test("attachments are cooked properly when secure media is enabled", async function (assert) {
await writeInComposer(assert);
assert.equal(
queryAll(".d-editor-preview:visible").html().trim(),
'<p><a class="attachment" href="/secure-media-uploads/default/3X/1/asjdiasjdiasida.png" tabindex="-1">test</a></p>'
);
});
});
acceptance("Composer Attachment - Upload Placeholder", function (needs) {
needs.user();
test("should insert a newline before and after an image when pasting into an empty composer", async function (assert) {
await visit("/");
await click("#create-topic");
const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
await queryAll(".wmd-controls").trigger("fileuploadsend", image);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: avatar.png...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image);
assert.equal(
queryAll(".d-editor-input").val(),
"![avatar|200x300](/images/avatar.png?1)\n"
);
});
test("should insert a newline after an image when pasting into a blank line", async function (assert) {
await visit("/");
await click("#create-topic");
await fillIn(".d-editor-input", "The image:\n");
const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
await queryAll(".wmd-controls").trigger("fileuploadsend", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image:\n[Uploading: avatar.png...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image:\n![avatar|200x300](/images/avatar.png?1)\n"
);
});
test("should insert a newline before and after an image when pasting into a non blank line", async function (assert) {
await visit("/");
await click("#create-topic");
await fillIn(".d-editor-input", "The image:");
const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
await queryAll(".wmd-controls").trigger("fileuploadsend", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image:\n[Uploading: avatar.png...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image:\n![avatar|200x300](/images/avatar.png?1)\n"
);
});
test("should insert a newline before and after an image when pasting with cursor in the middle of the line", async function (assert) {
await visit("/");
await click("#create-topic");
await fillIn(".d-editor-input", "The image Text after the image.");
const textArea = query(".d-editor-input");
textArea.selectionStart = 10;
textArea.selectionEnd = 10;
const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
await queryAll(".wmd-controls").trigger("fileuploadsend", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image \n[Uploading: avatar.png...]()\nText after the image."
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image \n![avatar|200x300](/images/avatar.png?1)\nText after the image."
);
});
test("should insert a newline before and after an image when pasting with text selected", async function (assert) {
await visit("/");
await click("#create-topic");
const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
await fillIn(
".d-editor-input",
"The image [paste here] Text after the image."
);
const textArea = query(".d-editor-input");
textArea.selectionStart = 10;
textArea.selectionEnd = 23;
await queryAll(".wmd-controls").trigger("fileuploadsend", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image \n[Uploading: avatar.png...]()\n Text after the image."
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image);
assert.equal(
queryAll(".d-editor-input").val(),
"The image \n![avatar|200x300](/images/avatar.png?1)\n Text after the image."
);
});
test("pasting several images", async function (assert) {
await visit("/");
await click("#create-topic");
const image1 = createImage("test.png", "/images/avatar.png?1", 200, 300);
const image2 = createImage("test.png", "/images/avatar.png?2", 100, 200);
const image3 = createImage("image.png", "/images/avatar.png?3", 300, 400);
const image4 = createImage("image.png", "/images/avatar.png?4", 300, 400);
await queryAll(".wmd-controls").trigger("fileuploadsend", image1);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: test.png...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploadsend", image2);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: test.png...]()\n[Uploading: test.png(1)...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploadsend", image4);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: test.png...]()\n[Uploading: test.png(1)...]()\n[Uploading: image.png...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploadsend", image3);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: test.png...]()\n[Uploading: test.png(1)...]()\n[Uploading: image.png...]()\n[Uploading: image.png(1)...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image2);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: test.png...]()\n![test|100x200](/images/avatar.png?2)\n[Uploading: image.png...]()\n[Uploading: image.png(1)...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image3);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: test.png...]()\n![test|100x200](/images/avatar.png?2)\n[Uploading: image.png...]()\n![image|300x400](/images/avatar.png?3)\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image1);
assert.equal(
queryAll(".d-editor-input").val(),
"![test|200x300](/images/avatar.png?1)\n![test|100x200](/images/avatar.png?2)\n[Uploading: image.png...]()\n![image|300x400](/images/avatar.png?3)\n"
);
});
test("should accept files with unescaped characters", async function (assert) {
await visit("/");
await click("#create-topic");
const image = createImage("ima++ge.png", "/images/avatar.png?4", 300, 400);
await queryAll(".wmd-controls").trigger("fileuploadsend", image);
assert.equal(
queryAll(".d-editor-input").val(),
"[Uploading: ima++ge.png...]()\n"
);
await queryAll(".wmd-controls").trigger("fileuploaddone", image);
assert.equal(
queryAll(".d-editor-input").val(),
"![ima++ge|300x400](/images/avatar.png?4)\n"
);
});
});
function createImage(name, url, width, height) {
const file = new Blob([""], { type: "image/png" });
file.name = name;
return {
files: [file],
result: {
original_filename: name,
thumbnail_width: width,
thumbnail_height: height,
url,
},
};
}
acceptance("Composer Attachment - Upload Handler", function (needs) {
needs.user();
needs.hooks.beforeEach(() => {
withPluginApi("0.8.14", (api) => {
api.addComposerUploadHandler(["png"], (file) => {
bootbox.alert(`This is an upload handler test for ${file.name}`);
});
});
});
test("should handle a single file being uploaded with the extension handler", async function (assert) {
await visit("/");
await click("#create-topic");
const image = createImage(
"handlertest.png",
"/images/avatar.png?1",
200,
300
);
await fillIn(".d-editor-input", "This is a handler test.");
await queryAll(".wmd-controls").trigger("fileuploadsubmit", image);
assert.equal(
queryAll(".bootbox .modal-body").html(),
"This is an upload handler test for handlertest.png",
"it should show the bootbox triggered by the upload handler"
);
await click(".modal-footer .btn");
});
});
acceptance("Composer Attachment - File input", function (needs) {
needs.user();
test("shouldn't add to DOM the hidden file input if uploads aren't allowed", async function (assert) {
this.siteSettings.authorized_extensions = "";
await visit("/");
await click("#create-topic");
assert.notOk(exists("input#file-uploader"));
});
test("should fill the accept attribute with allowed file extensions", async function (assert) {
this.siteSettings.authorized_extensions = "jpg|jpeg|png";
await visit("/");
await click("#create-topic");
assert.ok(exists("input#file-uploader"), "An input is rendered");
assert.equal(
query("input#file-uploader").accept,
".jpg,.jpeg,.png",
"Accepted values are correct"
);
});
test("the hidden file input shouldn't have the accept attribute if any file extension is allowed", async function (assert) {
this.siteSettings.authorized_extensions = "jpg|jpeg|png|*";
await visit("/");
await click("#create-topic");
assert.ok(exists("input#file-uploader"), "An input is rendered");
assert.notOk(
query("input#file-uploader").hasAttribute("accept"),
"The input doesn't contain the accept attribute"
);
});
});