[#70175] Better testing setup for BlockNote/Hocuspocus

https://community.openproject.org/work_packages/70175

This adds the capacity to run integration tests with a real Hocuspocus
backend (either locally or in docker).
This commit is contained in:
Judith Roth
2026-01-30 16:39:09 +01:00
parent 47bfe4bdf4
commit 7613e3f498
2 changed files with 114 additions and 0 deletions
+10
View File
@@ -123,6 +123,13 @@ services:
networks:
- testing
hocuspocus-test:
image: openproject/hocuspocus:latest
environment:
SECRET: secret12345
networks:
- testing
frontend-test:
build:
<<: *frontend-build
@@ -157,8 +164,11 @@ services:
condition: service_healthy
cuprite-chrome:
condition: service_started
hocuspocus-test:
condition: service_started
environment:
RAILS_ENV: test
OPENPROJECT_TESTING_WITH_DOCKER: "true"
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
DATABASE_URL: postgresql://openproject:openproject@db-test/openproject
DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: "true"
@@ -0,0 +1,104 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
require "spec_helper"
require_module_spec_helper
RSpec.describe "Real-time collaboration with Hocuspocus for documents",
:js,
:selenium do
let(:editor) { FormFields::Primerized::BlockNoteEditorInput.new }
let(:admin) { create(:admin, firstname: "Armin", lastname: "Admin") }
let(:member_role) { create(:existing_project_role, permissions: [:view_documents]) }
let(:readonly_user) { create(:user, member_with_roles: { project => member_role }, firstname: "Rita", lastname: "Readonly") }
let(:project) { create(:project) }
let(:document) { create(:document, :collaborative, project:) }
before do
# These tests require a running Hocuspocus server. You can either run one
# locally or use the docker test setup.
host = ENV["OPENPROJECT_TESTING_WITH_DOCKER"] == "true" ? "hocuspocus-test" : "127.0.0.1"
port = 1234
Setting.collaborative_editing_hocuspocus_url = "ws://#{host}:#{port}"
Setting.collaborative_editing_hocuspocus_secret = "secret12345"
begin
TCPSocket.new(host, port).close
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError => e
raise("Hocuspocus server not reachable at #{host}:#{port} - #{e.message}")
end
end
context "with write permission" do
before do
login_as(admin)
end
it "shows the editor" do
visit document_path(document)
expect(page).to have_test_selector("blocknote-document-description")
expect(page).to have_no_content("Armin Admin")
page.find_link("1 active editor").click
expect(page).to have_content("Armin Admin")
end
it "renders a collaborative document and saves changes to the database" do
visit document_path(document)
expect(document.content_binary).to be_nil
expect(page).to have_test_selector("blocknote-document-description")
editor.fill_in("Hello Hocuspocus")
wait_for { document.reload.content_binary }.to be_present
expect(document.description).to eq("Hello Hocuspocus\n")
end
end
context "with readonly permission" do
before do
login_as(readonly_user)
end
it "shows the editor but does not accept writes" do
# rubocop:disable Layout/LineLength
binary = "ARL108iNDAAHAQ5kb2N1bWVudC1zdG9yZQMKYmxvY2tHcm91cAcA9dPIjQwAAw5ibG9ja0NvbnRhaW5lcgcA9dPIjQwBAwlwYXJhZ3JhcGgHAPXTyI0MAgYEAPXTyI0MAwFIKAD108iNDAIPYmFja2dyb3VuZENvbG9yAXcHZGVmYXVsdCgA9dPIjQwCCXRleHRDb2xvcgF3B2RlZmF1bHQoAPXTyI0MAg10ZXh0QWxpZ25tZW50AXcEbGVmdCgA9dPIjQwBAmlkAXcOaW5pdGlhbEJsb2NrSWSH9dPIjQwBAw5ibG9ja0NvbnRhaW5lcgcA9dPIjQwJAwlwYXJhZ3JhcGgoAPXTyI0MCg9iYWNrZ3JvdW5kQ29sb3IBdwdkZWZhdWx0KAD108iNDAoJdGV4dENvbG9yAXcHZGVmYXVsdCgA9dPIjQwKDXRleHRBbGlnbm1lbnQBdwRsZWZ0KAD108iNDAkCaWQBdyQ4OTc0Yzk0YS1kZWZiLTRmMjEtYTc4Yi1mN2MyZTg5ZjUxZmKE9dPIjQwEBGVsbG+B9dPIjQwSAYT108iNDBMLIEhvY3VzcG9jdXMB9dPIjQwBEwE="
# rubocop:enable Layout/LineLength
document.update!(content_binary: binary, description: "Hello Hocuspocus\n")
visit document_path(document)
expect(page).to have_test_selector("blocknote-document-description")
wait_for { editor.content }.to have_content("Hello Hocuspocus")
editor.fill_in("Nothing changes")
# Hocuspocus takes some time before saving. It's hard to wait for
# something to not change, so this sleeps, although it's bad to do that in tests.
sleep 5 # rubocop:disable OpenProject/NoSleepInFeatureSpecs
expect(document.reload.content_binary).to eql(binary) # nothing changed
expect(document.description).to eq("Hello Hocuspocus\n")
end
end
end