Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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'
11 changes: 11 additions & 0 deletions spec/page_objects/admin/authors/edit_page.rb
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions spec/page_objects/admin/posts/edit_page.rb
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions spec/page_objects/base_object.rb
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions spec/page_objects/base_page.rb
Original file line number Diff line number Diff line change
@@ -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 changes: 35 additions & 0 deletions spec/page_objects/shared/html_editor.rb
Original file line number Diff line number Diff line change
@@ -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 changes: 44 additions & 0 deletions spec/page_objects/shared/quill_editor.rb
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
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
Expand Down
120 changes: 74 additions & 46 deletions spec/system/quill_editor_spec.rb
Original file line number Diff line number Diff line change
@@ -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
expect(page).to have_css('#post_description[data-aa-quill-editor]')
expect(page).to have_css('#post_description_input .ql-editor', text: 'Some content...')
before do
path = edit_admin_post_path(post)
Admin::Posts::EditPage.new(path: path).load
end

it 'adds some text to the description' do
visit "/admin/posts/#{post.id}/edit"
it 'adds some text to the description', :aggregate_failures do
expect(page).to have_css('#post_description[data-aa-quill-editor]')
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

find('#post_description_input .ql-editor').click
find('#post_description_input .ql-editor').base.send_keys('more text')
find('[type="submit"]').click
it 'adds some bold text to the description', :aggregate_failures do
editor.toolbar_control(:bold)
editor << 'Some bold text'

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"

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
it 'adds some italic text to the description', :aggregate_failures do
editor.toolbar_control(:italic)
editor << 'Some italic text'

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"

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')
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('[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