From 0a619d8c884e211955ef65b387023f0199aa43cb Mon Sep 17 00:00:00 2001 From: David Battersby Date: Thu, 23 Feb 2023 11:30:16 +0800 Subject: [PATCH] =?UTF-8?q?FIX:=20Fast=20edit=20doesn=E2=80=99t=20work=20o?= =?UTF-8?q?n=20content=20with=20certain=20characters=20(#20410)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Small js fix for fast edit to allow posts to save changes when the post contains apostrophes and quotation marks. Replaces unicode characters in text prior to saving the edit. Includes system tests for fast edit and introduces a new system spec component for fast edit usage. --- .../discourse/app/components/quote-button.js | 6 +- spec/support/system_helpers.rb | 15 +++++ spec/system/fast_edit_spec.rb | 55 +++++++++++++++++++ .../page_objects/components/fast_editor.rb | 28 ++++++++++ spec/system/page_objects/pages/topic.rb | 13 +++++ 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 spec/system/fast_edit_spec.rb create mode 100644 spec/system/page_objects/components/fast_editor.rb diff --git a/app/assets/javascripts/discourse/app/components/quote-button.js b/app/assets/javascripts/discourse/app/components/quote-button.js index 3c057ce72f7..c5a7038b4fb 100644 --- a/app/assets/javascripts/discourse/app/components/quote-button.js +++ b/app/assets/javascripts/discourse/app/components/quote-button.js @@ -39,9 +39,9 @@ function getQuoteTitle(element) { } function fixQuotes(str) { - // u+201c “ - // u+201d ” - return str.replace(/[\u201C\u201D]/g, '"'); + // u+201c, u+201d = “ ” + // u+2018, u+2019 = ‘ ’ + return str.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'"); } export default Component.extend(KeyEnterEscape, { diff --git a/spec/support/system_helpers.rb b/spec/support/system_helpers.rb index 336584a231c..a9d472a729b 100644 --- a/spec/support/system_helpers.rb +++ b/spec/support/system_helpers.rb @@ -80,4 +80,19 @@ module SystemHelpers def using_session(name, &block) Capybara.using_session(name.to_s + self.method_name, &block) end + + def select_text_range(selector, start = 0, offset = 5) + js = <<-JS + const node = document.querySelector(arguments[0]).childNodes[0]; + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(node); + range.setStart(node, arguments[1]); + range.setEnd(node, arguments[1] + arguments[2]); + selection.removeAllRanges(); + selection.addRange(range); + JS + + page.execute_script(js, selector, start, offset) + end end diff --git a/spec/system/fast_edit_spec.rb b/spec/system/fast_edit_spec.rb new file mode 100644 index 00000000000..38bcc4f2b72 --- /dev/null +++ b/spec/system/fast_edit_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +describe "Fast edit", type: :system, js: true do + let(:topic_page) { PageObjects::Pages::Topic.new } + let(:fast_editor) { PageObjects::Components::FastEditor.new } + fab!(:topic) { Fabricate(:topic) } + fab!(:post) { Fabricate(:post, topic: topic) } + fab!(:post_2) { Fabricate(:post, topic: topic, raw: "It ‘twas a great’ “time”!") } + fab!(:current_user) { Fabricate(:admin) } + + before { sign_in(current_user) } + + context "when text selected it opens contact menu and fast editor" do + it "opens context menu and fast edit dialog" do + topic_page.visit_topic(topic) + + select_text_range("#{topic_page.post_by_number_selector(1)} .cooked p", 0, 10) + expect(topic_page.fast_edit_button).to be_visible + + topic_page.click_fast_edit_button + expect(topic_page.fast_edit_input).to be_visible + end + + it "edits first paragraph and saves changes" do + topic_page.visit_topic(topic) + + select_text_range("#{topic_page.post_by_number_selector(1)} .cooked p", 0, 5) + topic_page.click_fast_edit_button + + fast_editor.fill_content("Howdy") + fast_editor.save + + within("#post_1 .cooked > p") do |el| + expect(el).not_to eq("Hello world") + expect(el).to have_content("Howdy") + end + end + end + + context "when editing text that has strange characters" do + it "saves when paragraph contains apostrophe" do + topic_page.visit_topic(topic) + + select_text_range("#{topic_page.post_by_number_selector(2)} .cooked p", 19, 4) + topic_page.click_fast_edit_button + + fast_editor.fill_content("day") + fast_editor.save + + expect(find("#{topic_page.post_by_number_selector(2)} .cooked p")).to have_content( + "It ‘twas a great’ “day”!", + ) + end + end +end diff --git a/spec/system/page_objects/components/fast_editor.rb b/spec/system/page_objects/components/fast_editor.rb new file mode 100644 index 00000000000..93ff5135a03 --- /dev/null +++ b/spec/system/page_objects/components/fast_editor.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module PageObjects + module Components + class FastEditor < PageObjects::Components::Base + def fill_content(content) + fast_edit_input.fill_in(with: content) + self + end + + def clear_content + fill_content("") + end + + def has_content?(content) + fast_edit_input.value == content + end + + def save + find(".save-fast-edit").click + end + + def fast_edit_input + find("#fast-edit-input") + end + end + end +end diff --git a/spec/system/page_objects/pages/topic.rb b/spec/system/page_objects/pages/topic.rb index f8633154681..a9a75c8ba67 100644 --- a/spec/system/page_objects/pages/topic.rb +++ b/spec/system/page_objects/pages/topic.rb @@ -5,6 +5,7 @@ module PageObjects class Topic < PageObjects::Pages::Base def initialize @composer_component = PageObjects::Components::Composer.new + @fast_edit_component = PageObjects::Components::FastEditor.new end def visit_topic(topic) @@ -114,6 +115,18 @@ module PageObjects @composer_component.fill_title(title) end + def fast_edit_button + find(".quote-button .quote-edit-label") + end + + def click_fast_edit_button + find(".quote-button .quote-edit-label").click + end + + def fast_edit_input + @fast_edit_component.fast_edit_input + end + private def topic_footer_button_id(button)