From b5d42f373b551b245fb8c57fec1b0638ca10ab98 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Wed, 16 Apr 2025 11:11:43 +1000 Subject: [PATCH] DEV: Re-introduce proofreading specs (#1263) Followup fe7e73a6a436795c053a611884431f663f4bdd27 and 1300cc8a36dc33870f0d3c81e1e1a21a93e1f1de Reintroduces proofreader specs and unskips ones skipped when streaming composer suggestions were added. We just need to make sure the jobs run immediately in specs because the job is what sends the MessageBus event to the UI. Also adds a pageobject method to confirm a diff is shown in the modal before pressing Confirm button. --- spec/system/ai_helper/ai_proofreading_spec.rb | 51 ++++++++++++++++--- spec/system/page_objects/modals/diff_modal.rb | 5 ++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/spec/system/ai_helper/ai_proofreading_spec.rb b/spec/system/ai_helper/ai_proofreading_spec.rb index 96b17127..b2e00733 100644 --- a/spec/system/ai_helper/ai_proofreading_spec.rb +++ b/spec/system/ai_helper/ai_proofreading_spec.rb @@ -8,36 +8,42 @@ RSpec.describe "AI Composer Proofreading Features", type: :system, js: true do before do assign_fake_provider_to(:ai_helper_model) SiteSetting.ai_helper_enabled = true + + # This needs to be done because the streaming suggestions for composer + # happen in a background job, which sends the MessageBus event to the client. + Jobs.run_immediately! sign_in(admin) end let(:composer) { PageObjects::Components::Composer.new } + let(:rich) { composer.rich_editor } let(:toasts) { PageObjects::Components::Toasts.new } let(:diff_modal) { PageObjects::Modals::DiffModal.new } + let(:keyboard_shortcut) { [PLATFORM_KEY_MODIFIER, :alt, "p"] } context "when triggering via keyboard shortcut" do - it "proofreads selected text using" do - skip("Message bus updates not appearing in tests") + it "proofreads selected text" do visit "/new-topic" composer.fill_content("hello worldd !") composer.select_range(6, 12) DiscourseAi::Completions::Llm.with_prepared_responses(["world"]) do - composer.composer_input.send_keys([PLATFORM_KEY_MODIFIER, :alt, "p"]) + composer.composer_input.send_keys(keyboard_shortcut) + expect(diff_modal).to have_diff("worldd", "world") diff_modal.confirm_changes expect(composer.composer_input.value).to eq("hello world !") end end it "proofreads all text when nothing is selected" do - skip("Message bus updates not appearing in tests") visit "/new-topic" composer.fill_content("hello worrld") # Simulate AI response DiscourseAi::Completions::Llm.with_prepared_responses(["hello world"]) do - composer.composer_input.send_keys([PLATFORM_KEY_MODIFIER, :alt, "p"]) + composer.composer_input.send_keys(keyboard_shortcut) + expect(diff_modal).to have_diff("worrld", "world") diff_modal.confirm_changes expect(composer.composer_input.value).to eq("hello world") end @@ -48,9 +54,42 @@ RSpec.describe "AI Composer Proofreading Features", type: :system, js: true do # Simulate AI response DiscourseAi::Completions::Llm.with_prepared_responses(["hello world"]) do - composer.composer_input.send_keys([PLATFORM_KEY_MODIFIER, :alt, "p"]) + composer.composer_input.send_keys(keyboard_shortcut) expect(toasts).to have_error(I18n.t("js.discourse_ai.ai_helper.no_content_error")) end end + + context "when using rich text editor" do + before { SiteSetting.rich_editor = true } + + it "proofreads selected text and replaces it" do + visit "/new-topic" + expect(composer).to be_opened + composer.toggle_rich_editor + composer.type_content("hello worldd !") + + # NOTE: The rich text editor cannot use select_range on the page object since it is + # a contenteditable element. It would be hard to make this generic enough to put in + # the page object, maybe at some point in the future we can refactor this. + execute_script(<<~JS, text) + const composer = document.querySelector("#reply-control .d-editor-input"); + const startNode = composer.firstChild.firstChild; + composer.focus(); + const range = document.createRange(); + range.setStart(startNode, 6); + range.setEnd(startNode, 12); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + JS + + DiscourseAi::Completions::Llm.with_prepared_responses(["world"]) do + composer.composer_input.send_keys(keyboard_shortcut) + expect(diff_modal).to have_diff("worldd", "world") + diff_modal.confirm_changes + expect(rich).to have_css("p", text: "hello world !") + end + end + end end end diff --git a/spec/system/page_objects/modals/diff_modal.rb b/spec/system/page_objects/modals/diff_modal.rb index e4faa486..4c6a5a27 100644 --- a/spec/system/page_objects/modals/diff_modal.rb +++ b/spec/system/page_objects/modals/diff_modal.rb @@ -22,6 +22,11 @@ module PageObjects def new_value find(".composer-ai-helper-modal__new-value").text end + + def has_diff?(old_value, new_value) + has_css?(".inline-diff ins", text: new_value) && + has_css?(".inline-diff del", text: old_value) + end end end end