"use strict"; const {strict: assert} = require("assert"); const {mock_esm, set_global, zrequire} = require("./lib/namespace"); const {run_test} = require("./lib/test"); const $ = require("./lib/zjquery"); const {page_params} = require("./lib/zpage_params"); set_global("navigator", { userAgent: "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)", }); let uppy_stub; mock_esm("@uppy/core", { Uppy: function Uppy(options) { return uppy_stub.call(this, options); }, }); mock_esm("@uppy/xhr-upload", {default: class XHRUpload {}}); const compose_actions = mock_esm("../src/compose_actions"); mock_esm("../src/csrf", {csrf_token: "csrf_token"}); const compose_ui = zrequire("compose_ui"); const upload = zrequire("upload"); function test(label, f) { run_test(label, (helpers) => { page_params.max_file_upload_size_mib = 25; return f(helpers); }); } test("feature_check", ({override}) => { const $upload_button = $.create("upload-button-stub"); $upload_button.addClass("notdisplayed"); upload.feature_check($upload_button); assert.ok($upload_button.hasClass("notdisplayed")); override(window, "XMLHttpRequest", () => ({upload: true})); upload.feature_check($upload_button); assert.ok(!$upload_button.hasClass("notdisplayed")); }); test("get_item", () => { assert.equal(upload.get_item("textarea", {mode: "compose"}), $("#compose-textarea")); assert.equal( upload.get_item("upload_banner_message", {mode: "compose"}), $("#compose_banners .upload_banner .upload_msg"), ); assert.equal( upload.get_item("upload_banner_close_button", {mode: "compose"}), $("#compose_banners .upload_banner .compose_banner_close_button"), ); assert.equal( upload.get_item("file_input_identifier", {mode: "compose"}), "#compose .file_input", ); assert.equal(upload.get_item("source", {mode: "compose"}), "compose-file-input"); assert.equal(upload.get_item("drag_drop_container", {mode: "compose"}), $("#compose")); assert.equal( upload.get_item("markdown_preview_hide_button", {mode: "compose"}), $("#compose .undo_markdown_preview"), ); assert.equal( upload.get_item("textarea", {mode: "edit", row: 1}), $(`#edit_form_${CSS.escape(1)} .message_edit_content`), ); $(`#edit_form_${CSS.escape(2)} .message_edit_content`).closest = () => { $(".message_edit_form").set_find_results(".message_edit_save", $(".message_edit_save")); return $(".message_edit_form"); }; assert.equal(upload.get_item("send_button", {mode: "edit", row: 2}), $(".message_edit_save")); assert.equal( upload.get_item("upload_banner_identifier", {mode: "edit", row: 11}), `#edit_form_${CSS.escape(11)} .upload_banner`, ); assert.equal( upload.get_item("upload_banner", {mode: "edit", row: 75}), $(`#edit_form_${CSS.escape(75)} .upload_banner`), ); $(`#edit_form_${CSS.escape(2)} .upload_banner`).set_find_results( ".compose_banner_close_button", $(".compose_banner_close_button"), ); assert.equal( upload.get_item("upload_banner_close_button", {mode: "edit", row: 2}), $(`#edit_form_${CSS.escape(2)} .upload_banner .compose_banner_close_button`), ); $(`#edit_form_${CSS.escape(22)} .upload_banner`).set_find_results( ".upload_msg", $(".upload_msg"), ); assert.equal( upload.get_item("upload_banner_message", {mode: "edit", row: 22}), $(`#edit_form_${CSS.escape(22)} .upload_banner .upload_msg`), ); assert.equal( upload.get_item("file_input_identifier", {mode: "edit", row: 123}), `#edit_form_${CSS.escape(123)} .file_input`, ); assert.equal(upload.get_item("source", {mode: "edit", row: 123}), "message-edit-file-input"); assert.equal( upload.get_item("drag_drop_container", {mode: "edit", row: 1}), $(`#zfilt${CSS.escape(1)} .message_edit_form`), ); assert.equal( upload.get_item("markdown_preview_hide_button", {mode: "edit", row: 65}), $(`#edit_form_${CSS.escape(65)} .undo_markdown_preview`), ); assert.throws( () => { upload.get_item("textarea"); }, { name: "Error", message: "Missing config", }, ); assert.throws( () => { upload.get_item("textarea", {mode: "edit"}); }, { name: "Error", message: "Missing row in config", }, ); assert.throws( () => { upload.get_item("textarea", {mode: "blah"}); }, { name: "Error", message: "Invalid upload mode!", }, ); assert.throws( () => { upload.get_item("invalid", {mode: "compose"}); }, { name: "Error", message: 'Invalid key name for mode "compose"', }, ); assert.throws( () => { upload.get_item("invalid", {mode: "edit", row: 20}); }, { name: "Error", message: 'Invalid key name for mode "edit"', }, ); }); test("hide_upload_status", () => { let banner_removed = false; $("#compose_banners .upload_banner").remove = () => { banner_removed = true; }; $("#compose-send-button").prop("disabled", true); upload.hide_upload_status({mode: "compose"}); assert.ok(banner_removed); assert.equal($("#compose-send-button").prop("disabled"), false); assert.equal($("#compose-send-button").visible(), false); }); test("show_error_message", ({mock_template}) => { $("#compose_banners .upload_banner .moving_bar").css = () => {}; $("#compose_banners .upload_banner").length = 0; let banner_shown = false; mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "error"); assert.equal(data.banner_text, "Error message"); banner_shown = true; }); $("#compose-send-button").prop("disabled", true); upload.show_error_message({mode: "compose"}, "Error message"); assert.equal($("#compose-send-button").prop("disabled"), false); assert.ok(banner_shown); mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "error"); assert.equal(data.banner_text, "translated: An unknown error occurred."); banner_shown = true; }); upload.show_error_message({mode: "compose"}); }); test("upload_files", async ({mock_template, override_rewire}) => { $("#compose_banners .upload_banner").remove = () => {}; $("#compose_banners .upload_banner .moving_bar").css = () => {}; $("#compose_banners .upload_banner").length = 0; let uppy_cancel_all_called = false; let files = [ { name: "budapest.png", type: "image/png", }, ]; let uppy_add_file_called = false; const uppy = { cancelAll() { uppy_cancel_all_called = true; }, addFile(params) { uppy_add_file_called = true; assert.equal(params.source, "compose-file-input"); assert.equal(params.name, "budapest.png"); assert.equal(params.type, "image/png"); assert.equal(params.data, files[0]); }, getFiles: () => [...files], }; let hide_upload_status_called = false; override_rewire(upload, "hide_upload_status", (config) => { hide_upload_status_called = true; assert.equal(config.mode, "compose"); }); const config = {mode: "compose"}; $("#compose-send-button").prop("disabled", false); await upload.upload_files(uppy, config, []); assert.ok(!$("#compose-send-button").prop("disabled")); let banner_shown = false; mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "error"); assert.equal( data.banner_text, "translated: File and image uploads have been disabled for this organization.", ); banner_shown = true; }); page_params.max_file_upload_size_mib = 0; $("#compose_banners .upload_banner .upload_msg").text(""); await upload.upload_files(uppy, config, files); assert.ok(banner_shown); page_params.max_file_upload_size_mib = 25; let on_click_close_button_callback; $("#compose_banners .upload_banner .compose_banner_close_button").one = (event, callback) => { assert.equal(event, "click"); on_click_close_button_callback = callback; }; let compose_ui_insert_syntax_and_focus_called = false; override_rewire(compose_ui, "insert_syntax_and_focus", (syntax, textarea) => { assert.equal(syntax, "[translated: Uploading budapest.png…]()"); assert.equal(textarea, $("#compose-textarea")); compose_ui_insert_syntax_and_focus_called = true; }); let compose_ui_autosize_textarea_called = false; override_rewire(compose_ui, "autosize_textarea", () => { compose_ui_autosize_textarea_called = true; }); let markdown_preview_hide_button_clicked = false; $("#compose .undo_markdown_preview").on("click", () => { markdown_preview_hide_button_clicked = true; }); $("#compose-send-button").prop("disabled", false); $("#compose_banners .upload_banner").remove(); $("#compose .undo_markdown_preview").show(); banner_shown = false; mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "info"); assert.equal(data.banner_text, "translated: Uploading…"); banner_shown = true; }); await upload.upload_files(uppy, config, files); assert.ok($("#compose-send-button").prop("disabled")); assert.ok(banner_shown); assert.ok(compose_ui_insert_syntax_and_focus_called); assert.ok(compose_ui_autosize_textarea_called); assert.ok(markdown_preview_hide_button_clicked); assert.ok(uppy_add_file_called); banner_shown = false; files = [ { name: "budapest.png", type: "image/png", }, { name: "prague.png", type: "image/png", }, ]; let add_file_counter = 0; uppy.addFile = (file) => { assert.equal(file.name, "budapest.png"); add_file_counter += 1; throw new Error("some error"); }; await upload.upload_files(uppy, config, files); assert.ok(banner_shown); assert.equal(add_file_counter, 1); hide_upload_status_called = false; uppy_cancel_all_called = false; let compose_ui_replace_syntax_called = false; files = [ { name: "budapest.png", type: "image/png", }, ]; override_rewire(compose_ui, "replace_syntax", (old_syntax, new_syntax, textarea) => { compose_ui_replace_syntax_called = true; assert.equal(old_syntax, "[translated: Uploading budapest.png…]()"); assert.equal(new_syntax, ""); assert.equal(textarea, $("#compose-textarea")); }); on_click_close_button_callback(); assert.ok(uppy_cancel_all_called); assert.ok(hide_upload_status_called); assert.ok(compose_ui_autosize_textarea_called); assert.ok(compose_ui_replace_syntax_called); hide_upload_status_called = false; compose_ui_replace_syntax_called = false; $("#compose-textarea").val("user modified text"); on_click_close_button_callback(); assert.ok(hide_upload_status_called); assert.ok(compose_ui_autosize_textarea_called); assert.ok(compose_ui_replace_syntax_called); assert.equal($("#compose-textarea").val(), "user modified text"); }); test("uppy_config", () => { let uppy_stub_called = false; let uppy_set_meta_called = false; let uppy_used_xhrupload = false; uppy_stub = function (config) { uppy_stub_called = true; assert.equal(config.debug, false); assert.equal(config.autoProceed, true); assert.equal(config.restrictions.maxFileSize, 25 * 1024 * 1024); assert.equal(Object.keys(config.locale.strings).length, 2); assert.ok("exceedsSize" in config.locale.strings); return { setMeta(params) { uppy_set_meta_called = true; assert.equal(params.csrfmiddlewaretoken, "csrf_token"); }, use(func, params) { const func_name = func.name; if (func_name === "XHRUpload") { uppy_used_xhrupload = true; assert.equal(params.endpoint, "/json/user_uploads"); assert.equal(params.formData, true); assert.equal(params.fieldName, "file"); assert.equal(params.limit, 5); assert.equal(Object.keys(params.locale.strings).length, 1); assert.ok("timedOut" in params.locale.strings); } else { /* istanbul ignore next */ assert.fail(`Missing tests for ${func_name}`); } }, on() {}, }; }; upload.setup_upload({mode: "compose"}); assert.equal(uppy_stub_called, true); assert.equal(uppy_set_meta_called, true); assert.equal(uppy_used_xhrupload, true); }); test("file_input", ({override_rewire}) => { upload.setup_upload({mode: "compose"}); const change_handler = $("body").get_on_handler("change", "#compose .file_input"); const files = ["file1", "file2"]; const event = { target: { files, value: "C:\\fakepath\\portland.png", }, }; let upload_files_called = false; override_rewire(upload, "upload_files", (uppy, config, files) => { assert.equal(config.mode, "compose"); assert.equal(files, files); upload_files_called = true; }); change_handler(event); assert.ok(upload_files_called); }); test("file_drop", ({override_rewire}) => { upload.setup_upload({mode: "compose"}); let prevent_default_counter = 0; const drag_event = { preventDefault() { prevent_default_counter += 1; }, }; const dragover_handler = $("#compose").get_on_handler("dragover"); dragover_handler(drag_event); assert.equal(prevent_default_counter, 1); const dragenter_handler = $("#compose").get_on_handler("dragenter"); dragenter_handler(drag_event); assert.equal(prevent_default_counter, 2); const files = ["file1", "file2"]; const drop_event = { preventDefault() { prevent_default_counter += 1; }, originalEvent: { dataTransfer: { files, }, }, }; const drop_handler = $("#compose").get_on_handler("drop"); let upload_files_called = false; override_rewire(upload, "upload_files", () => { upload_files_called = true; }); drop_handler(drop_event); assert.equal(prevent_default_counter, 3); assert.equal(upload_files_called, true); }); test("copy_paste", ({override_rewire}) => { upload.setup_upload({mode: "compose"}); const paste_handler = $("#compose").get_on_handler("paste"); let get_as_file_called = false; let event = { originalEvent: { clipboardData: { items: [ { kind: "file", getAsFile() { get_as_file_called = true; }, }, { kind: "notfile", }, ], }, }, }; let upload_files_called = false; override_rewire(upload, "upload_files", () => { upload_files_called = true; }); paste_handler(event); assert.ok(get_as_file_called); assert.ok(upload_files_called); upload_files_called = false; event = { originalEvent: {}, }; paste_handler(event); assert.equal(upload_files_called, false); }); test("uppy_events", ({override, override_rewire, mock_template}) => { $("#compose_banners .upload_banner .moving_bar").css = () => {}; $("#compose_banners .upload_banner").length = 0; const callbacks = {}; let uppy_cancel_all_called = false; let state = {}; let files = []; uppy_stub = function () { return { setMeta() {}, use() {}, cancelAll() { uppy_cancel_all_called = true; }, on(event_name, callback) { callbacks[event_name] = callback; }, getFiles: () => [...files], removeFile(file_id) { files = files.filter((file) => file.id !== file_id); }, getState: () => ({ info: [ { type: state.type, details: state.details, message: state.message, }, ], }), }; }; upload.setup_upload({mode: "compose"}); assert.equal(Object.keys(callbacks).length, 6); const on_upload_success_callback = callbacks["upload-success"]; const file = { name: "copenhagen.png", }; let response = { body: { uri: "/user_uploads/4/cb/rue1c-MlMUjDAUdkRrEM4BTJ/copenhagen.png", }, }; let compose_actions_start_called = false; override(compose_actions, "start", () => { compose_actions_start_called = true; }); let compose_ui_replace_syntax_called = false; override_rewire(compose_ui, "replace_syntax", (old_syntax, new_syntax, textarea) => { compose_ui_replace_syntax_called = true; assert.equal(old_syntax, "[translated: Uploading copenhagen.png…]()"); assert.equal( new_syntax, "[copenhagen.png](/user_uploads/4/cb/rue1c-MlMUjDAUdkRrEM4BTJ/copenhagen.png)", ); assert.equal(textarea, $("#compose-textarea")); }); let compose_ui_autosize_textarea_called = false; override_rewire(compose_ui, "autosize_textarea", () => { compose_ui_autosize_textarea_called = true; }); on_upload_success_callback(file, response); assert.ok(compose_actions_start_called); assert.ok(compose_ui_replace_syntax_called); assert.ok(compose_ui_autosize_textarea_called); response = { body: { uri: undefined, }, }; compose_actions_start_called = false; compose_ui_replace_syntax_called = false; compose_ui_autosize_textarea_called = false; on_upload_success_callback(file, response); assert.equal(compose_actions_start_called, false); assert.equal(compose_ui_replace_syntax_called, false); assert.equal(compose_ui_autosize_textarea_called, false); const on_complete_callback = callbacks.complete; set_global("setTimeout", (func) => { func(); }); let hide_upload_status_called = false; override_rewire(upload, "hide_upload_status", () => { hide_upload_status_called = true; }); $("#compose_banner .upload_banner").removeClass("error"); files = [ { id: "uppy-zulip/jpeg-1e-image/jpeg-163515-1578367331279", progress: { uploadComplete: true, }, }, { id: "uppy-github/avatar/png-2v-1e-image/png-329746-1576507125831", progress: { uploadComplete: true, }, }, ]; on_complete_callback(); assert.ok(hide_upload_status_called); assert.equal(files.length, 0); hide_upload_status_called = false; $("#compose_banners .upload_banner").addClass("error"); on_complete_callback(); assert.ok(!hide_upload_status_called); $("#compose_banners .upload_banner").removeClass("error"); hide_upload_status_called = false; files = [ { id: "uppy-zulip/jpeg-1e-image/jpeg-163515-1578367331279", progress: { uploadComplete: true, }, }, { id: "uppy-github/avatar/png-2v-1e-image/png-329746-1576507125831", progress: { uploadComplete: false, }, }, ]; on_complete_callback(); assert.ok(!hide_upload_status_called); assert.equal(files.length, 1); mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "error"); assert.equal(data.banner_text, "Some error message"); }); state = { type: "error", details: "Some error", message: "Some error message", }; const on_info_visible_callback = callbacks["info-visible"]; $("#compose_banners .upload_banner .upload_msg").text(""); uppy_cancel_all_called = false; compose_ui_replace_syntax_called = false; const on_restriction_failed_callback = callbacks["restriction-failed"]; on_info_visible_callback(); assert.ok(uppy_cancel_all_called); override_rewire(compose_ui, "replace_syntax", (old_syntax, new_syntax, textarea) => { compose_ui_replace_syntax_called = true; assert.equal(old_syntax, "[translated: Uploading copenhagen.png…]()"); assert.equal(new_syntax, ""); assert.equal(textarea, $("#compose-textarea")); }); on_restriction_failed_callback(file, null, null); assert.ok(compose_ui_replace_syntax_called); compose_ui_replace_syntax_called = false; $("#compose-textarea").val("user modified text"); on_restriction_failed_callback(file, null, null); assert.ok(compose_ui_replace_syntax_called); assert.equal($("#compose-textarea").val(), "user modified text"); state = { type: "error", message: "No Internet connection", }; uppy_cancel_all_called = false; on_info_visible_callback(); state = { type: "error", details: "Upload Error", }; uppy_cancel_all_called = false; on_info_visible_callback(); const on_upload_error_callback = callbacks["upload-error"]; $("#compose_banners .upload_banner .upload_msg").text(""); mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "error"); assert.equal(data.banner_text, "Response message"); }); compose_ui_replace_syntax_called = false; response = { body: { msg: "Response message", }, }; uppy_cancel_all_called = false; on_upload_error_callback(file, null, response); assert.ok(uppy_cancel_all_called); assert.ok(compose_ui_replace_syntax_called); mock_template("compose_banner/upload_banner.hbs", false, (data) => { assert.equal(data.banner_type, "error"); assert.equal(data.banner_text, "translated: An unknown error occurred."); }); compose_ui_replace_syntax_called = false; uppy_cancel_all_called = false; on_upload_error_callback(file, null, null); assert.ok(uppy_cancel_all_called); assert.ok(compose_ui_replace_syntax_called); $("#compose_banners .upload_banner .upload_msg").text(""); $("#compose-textarea").val("user modified text"); uppy_cancel_all_called = false; on_upload_error_callback(file, null); assert.ok(uppy_cancel_all_called); assert.ok(compose_ui_replace_syntax_called); assert.equal($("#compose-textarea").val(), "user modified text"); });