Merge pull request #52 from blocknotes/test/improve-specs

test: Improve specs using page objects
Этот коммит содержится в:
Mattia Roccoberton
2025-03-16 18:30:55 +01:00
коммит произвёл GitHub
родитель bbee6f7681 21ec7a918b
Коммит bd32c5f28f
10 изменённых файлов: 211 добавлений и 48 удалений

Просмотреть файл

@@ -2,11 +2,15 @@
inherit_from:
- https://relaxed.ruby.style/rubocop.yml
require:
- rubocop-packaging
plugins:
- rubocop-capybara
- rubocop-performance
- rubocop-rails
- rubocop-rspec
- rubocop-rspec_rails
require:
- rubocop-packaging
AllCops:
Exclude:

Просмотреть файл

@@ -38,10 +38,12 @@ gem 'rspec-retry'
# Linters
gem 'fasterer'
gem 'rubocop'
gem 'rubocop-capybara'
gem 'rubocop-packaging'
gem 'rubocop-performance'
gem 'rubocop-rails'
gem 'rubocop-rspec'
gem 'rubocop-rspec_rails'
# Tools
gem 'pry-rails'

Просмотреть файл

@@ -0,0 +1,11 @@
# frozen_string_literal: true
require_relative '../../base_page'
module Admin
module Authors
class EditPage < BasePage
include Capybara::DSL
end
end
end

11
spec/page_objects/admin/posts/edit_page.rb Обычный файл
Просмотреть файл

@@ -0,0 +1,11 @@
# frozen_string_literal: true
require_relative '../../base_page'
module Admin
module Posts
class EditPage < BasePage
include Capybara::DSL
end
end
end

12
spec/page_objects/base_object.rb Обычный файл
Просмотреть файл

@@ -0,0 +1,12 @@
# frozen_string_literal: true
class BaseObject
include Capybara::DSL
attr_reader :element, :selector
def initialize(selector:)
@selector = selector
@element = find(selector)
end
end

15
spec/page_objects/base_page.rb Обычный файл
Просмотреть файл

@@ -0,0 +1,15 @@
# frozen_string_literal: true
class BasePage
include Capybara::DSL
attr_reader :path
def initialize(path:)
@path = path
end
def load
visit(path)
end
end

35
spec/page_objects/shared/html_editor.rb Обычный файл
Просмотреть файл

@@ -0,0 +1,35 @@
# frozen_string_literal: true
require_relative '../base_object'
class HtmlEditor < BaseObject
def content_element
raise NotImplementedError
end
def clear
select_all
content_element.send_keys(:delete)
self
end
# @return [self]
def open_dropdown
raise NotImplementedError
end
def select_all
content_element.send_keys([:control, "a"])
self
end
def toolbar_control(control, ...)
send(:"toggle_#{control}", ...)
self
end
def <<(content)
content_element.send_keys(content)
self
end
end

44
spec/page_objects/shared/quill_editor.rb Обычный файл
Просмотреть файл

@@ -0,0 +1,44 @@
# frozen_string_literal: true
class QuillEditor < HtmlEditor
SELECTOR = '.ql-container'
TOOLBAR_SELECTOR = '.ql-toolbar'
attr_reader :toolbar, :toolbar_selector
def initialize(selector: SELECTOR, toolbar_selector: TOOLBAR_SELECTOR)
super(selector: selector)
@toolbar = find(toolbar_selector)
@toolbar_selector = toolbar_selector
end
def content_element
@content_element ||= find("#{selector} .ql-editor")
end
def control_selector(control)
case control&.to_sym
when :bold then "#{toolbar_selector} button.ql-bold"
when :italic then "#{toolbar_selector} button.ql-italic"
when :underline then "#{toolbar_selector} button.ql-underline"
when :link then "#{toolbar_selector} button.ql-link"
else raise "Invalid control #{control}"
end
end
def toggle_bold
find(control_selector(:bold)).click
end
def toggle_italic
find(control_selector(:italic)).click
end
def toggle_underline
find(control_selector(:underline)).click
end
def toggle_link
find(control_selector(:link)).click
end
end

Просмотреть файл

@@ -12,7 +12,8 @@ require 'rspec/rails'
require 'capybara/rails'
require 'rspec/retry'
Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require_relative f }
Rails.root.glob("../support/**/*.rb").each { |f| require_relative f }
Rails.root.glob("../page_objects/**/*.rb").each { |f| require_relative f }
# Force deprecations to raise an exception.
# ActiveSupport::Deprecation.behavior = :raise

Просмотреть файл

@@ -1,86 +1,114 @@
# frozen_string_literal: true
RSpec.describe 'Quill editor' do
def lookup_editor(field:)
selector = ["##{field}_input.quill_editor", QuillEditor::SELECTOR].join(' ')
toolbar_selector = ["##{field}_input.quill_editor", QuillEditor::TOOLBAR_SELECTOR].join(' ')
QuillEditor.new(selector: selector, toolbar_selector: toolbar_selector)
end
let(:author) { Author.create!(email: 'some_email@example.com', name: 'John Doe', age: 30) }
let!(:post) { Post.create!(title: 'Test', author: author, description: 'Some content...') }
let!(:post) { Post.create!(title: 'Test', author: author, description: '') }
context 'with a Quill editor' do
it 'initialize the editor' do
visit "/admin/posts/#{post.id}/edit"
let(:editor) { lookup_editor(field: 'post_description') }
%w[bold italic underline link].each do |button|
expect(page).to have_css(".ql-toolbar button.ql-#{button}")
end
before do
path = edit_admin_post_path(post)
Admin::Posts::EditPage.new(path: path).load
end
it 'adds some text to the description', :aggregate_failures do
expect(page).to have_css('#post_description[data-aa-quill-editor]')
expect(page).to have_css('#post_description_input .ql-editor', text: 'Some content...')
editor << 'Some content...'
%i[bold italic underline link].each do |control|
expect(page).to have_css editor.control_selector(control)
end
expect(editor.content_element).to have_content('Some content...')
expect { find('[type="submit"]').click }
.to change { post.reload.description }.to '<p>Some content...</p>'
end
it 'adds some text to the description' do
visit "/admin/posts/#{post.id}/edit"
it 'adds some bold text to the description', :aggregate_failures do
editor.toolbar_control(:bold)
editor << 'Some bold text'
find('#post_description_input .ql-editor').click
find('#post_description_input .ql-editor').base.send_keys('more text')
find('[type="submit"]').click
expect(page).to have_content('was successfully updated')
expect(post.reload.description).to eq '<p>Some content...more text</p>'
expect(editor.content_element).to have_content('Some bold text')
expect { find('[type="submit"]').click }
.to change { post.reload.description }.to '<p><strong>Some bold text</strong></p>'
end
it 'adds some bold text to the description' do
visit "/admin/posts/#{post.id}/edit"
it 'adds some italic text to the description', :aggregate_failures do
editor.toolbar_control(:italic)
editor << 'Some italic text'
find('#post_description_input .ql-editor').click
find('#post_description_input .ql-toolbar .ql-bold').click
find('#post_description_input .ql-editor').base.send_keys('more text')
find('[type="submit"]').click
expect(post.reload.description).to eq '<p>Some content...<strong>more text</strong></p>'
expect(editor.content_element).to have_content('Some italic text')
expect { find('[type="submit"]').click }
.to change { post.reload.description }.to '<p><em>Some italic text</em></p>'
end
it 'adds some italic text to the description' do
visit "/admin/posts/#{post.id}/edit"
it 'adds some underline text to the description', :aggregate_failures do
editor.toolbar_control(:underline)
editor << 'Some underline text'
find('#post_description_input .ql-editor').click
find('#post_description_input .ql-toolbar .ql-italic').click
find('#post_description_input .ql-editor').base.send_keys('more text')
find('[type="submit"]').click
expect(editor.content_element).to have_content('Some underline text')
expect { find('[type="submit"]').click }
.to change { post.reload.description }.to '<p><u>Some underline text</u></p>'
end
expect(post.reload.description).to eq '<p>Some content...<em>more text</em></p>'
it 'adds a link to the description', :aggregate_failures do
editor << "Just a link"
editor.select_all
editor.toolbar_control(:link)
editor.element.find('[data-link]').send_keys("https://www.google.com", :return)
expect(editor.content_element).to have_content('Just a link')
html = '<p><a href="Just a linkhttps://www.google.com" rel="noopener noreferrer" target="_blank">Just a link</a></p>'
expect { find('[type="submit"]').click }.to change { post.reload.description }.to html
end
end
context 'with 2 Quill editors' do
it 'updates some HTML content for 2 fields' do
visit "/admin/posts/#{post.id}/edit"
before do
path = edit_admin_post_path(post)
Admin::Posts::EditPage.new(path: path).load
end
it 'updates some HTML content for 2 fields', :aggregate_failures do
editor1 = lookup_editor(field: 'post_description')
editor1.clear.toolbar_control(:bold)
editor1 << "Some description"
editor2 = lookup_editor(field: 'post_summary')
editor2.clear.toolbar_control(:italic)
editor2 << "Some summary"
find('#post_description_input .ql-editor').click
find('#post_description_input .ql-toolbar .ql-bold').click
find('#post_description_input .ql-editor').base.send_keys('more text')
find('#post_summary_input .ql-editor').click
find('#post_summary_input .ql-toolbar .ql-italic').click
find('#post_summary_input .ql-editor').base.send_keys('Summary text')
find('[type="submit"]').click
post.reload
expect(post.description).to eq '<p>Some content...<strong>more text</strong></p>'
expect(post.summary).to eq '<p><em>Summary text</em></p>'
expect(post.description).to eq '<p><strong>Some description</strong></p>'
expect(post.summary).to eq '<p><em>Some summary</em></p>'
end
end
context 'with a Quill editor in a nested resource' do
it 'updates some HTML content of a new nested resource' do
visit "/admin/authors/#{author.id}/edit"
before do
path = edit_admin_author_path(author)
Admin::Authors::EditPage.new(path: path).load
end
expect(page).to have_css('.posts.has_many_container .ql-editor', text: 'Some content...')
it 'updates some HTML content of a new nested resource', :aggregate_failures do
find('.posts.has_many_container .has_many_add').click
expect(page).to have_css('.posts.has_many_container .ql-editor', count: 2)
editor = lookup_editor(field: 'author_posts_attributes_1_description')
editor << "Some post text"
fill_in('author[posts_attributes][1][title]', with: 'A new post')
find('#author_posts_attributes_1_description_input .ql-editor').base.send_keys('new post text')
find('[type="submit"]').click
expect(page).to have_content('was successfully updated')
expect(author.posts.last.description).to eq '<p>new post text</p>'
expect(author.posts.last.description).to eq '<p>Some post text</p>'
end
end
end