Skip to content

Commit bd32c5f

Browse files
authored
Merge pull request #52 from blocknotes/test/improve-specs
test: Improve specs using page objects
2 parents bbee6f7 + 21ec7a9 commit bd32c5f

10 files changed

Lines changed: 212 additions & 49 deletions

File tree

.rubocop.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
inherit_from:
33
- https://relaxed.ruby.style/rubocop.yml
44

5-
require:
6-
- rubocop-packaging
5+
plugins:
6+
- rubocop-capybara
77
- rubocop-performance
88
- rubocop-rails
99
- rubocop-rspec
10+
- rubocop-rspec_rails
11+
12+
require:
13+
- rubocop-packaging
1014

1115
AllCops:
1216
Exclude:

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ gem 'rspec-retry'
3838
# Linters
3939
gem 'fasterer'
4040
gem 'rubocop'
41+
gem 'rubocop-capybara'
4142
gem 'rubocop-packaging'
4243
gem 'rubocop-performance'
4344
gem 'rubocop-rails'
4445
gem 'rubocop-rspec'
46+
gem 'rubocop-rspec_rails'
4547

4648
# Tools
4749
gem 'pry-rails'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../../base_page'
4+
5+
module Admin
6+
module Authors
7+
class EditPage < BasePage
8+
include Capybara::DSL
9+
end
10+
end
11+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../../base_page'
4+
5+
module Admin
6+
module Posts
7+
class EditPage < BasePage
8+
include Capybara::DSL
9+
end
10+
end
11+
end

spec/page_objects/base_object.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
class BaseObject
4+
include Capybara::DSL
5+
6+
attr_reader :element, :selector
7+
8+
def initialize(selector:)
9+
@selector = selector
10+
@element = find(selector)
11+
end
12+
end

spec/page_objects/base_page.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
class BasePage
4+
include Capybara::DSL
5+
6+
attr_reader :path
7+
8+
def initialize(path:)
9+
@path = path
10+
end
11+
12+
def load
13+
visit(path)
14+
end
15+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../base_object'
4+
5+
class HtmlEditor < BaseObject
6+
def content_element
7+
raise NotImplementedError
8+
end
9+
10+
def clear
11+
select_all
12+
content_element.send_keys(:delete)
13+
self
14+
end
15+
16+
# @return [self]
17+
def open_dropdown
18+
raise NotImplementedError
19+
end
20+
21+
def select_all
22+
content_element.send_keys([:control, "a"])
23+
self
24+
end
25+
26+
def toolbar_control(control, ...)
27+
send(:"toggle_#{control}", ...)
28+
self
29+
end
30+
31+
def <<(content)
32+
content_element.send_keys(content)
33+
self
34+
end
35+
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# frozen_string_literal: true
2+
3+
class QuillEditor < HtmlEditor
4+
SELECTOR = '.ql-container'
5+
TOOLBAR_SELECTOR = '.ql-toolbar'
6+
7+
attr_reader :toolbar, :toolbar_selector
8+
9+
def initialize(selector: SELECTOR, toolbar_selector: TOOLBAR_SELECTOR)
10+
super(selector: selector)
11+
@toolbar = find(toolbar_selector)
12+
@toolbar_selector = toolbar_selector
13+
end
14+
15+
def content_element
16+
@content_element ||= find("#{selector} .ql-editor")
17+
end
18+
19+
def control_selector(control)
20+
case control&.to_sym
21+
when :bold then "#{toolbar_selector} button.ql-bold"
22+
when :italic then "#{toolbar_selector} button.ql-italic"
23+
when :underline then "#{toolbar_selector} button.ql-underline"
24+
when :link then "#{toolbar_selector} button.ql-link"
25+
else raise "Invalid control #{control}"
26+
end
27+
end
28+
29+
def toggle_bold
30+
find(control_selector(:bold)).click
31+
end
32+
33+
def toggle_italic
34+
find(control_selector(:italic)).click
35+
end
36+
37+
def toggle_underline
38+
find(control_selector(:underline)).click
39+
end
40+
41+
def toggle_link
42+
find(control_selector(:link)).click
43+
end
44+
end

spec/rails_helper.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
require 'capybara/rails'
1313
require 'rspec/retry'
1414

15-
Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require_relative f }
15+
Rails.root.glob("../support/**/*.rb").each { |f| require_relative f }
16+
Rails.root.glob("../page_objects/**/*.rb").each { |f| require_relative f }
1617

1718
# Force deprecations to raise an exception.
1819
# ActiveSupport::Deprecation.behavior = :raise

spec/system/quill_editor_spec.rb

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,114 @@
11
# frozen_string_literal: true
22

33
RSpec.describe 'Quill editor' do
4+
def lookup_editor(field:)
5+
selector = ["##{field}_input.quill_editor", QuillEditor::SELECTOR].join(' ')
6+
toolbar_selector = ["##{field}_input.quill_editor", QuillEditor::TOOLBAR_SELECTOR].join(' ')
7+
QuillEditor.new(selector: selector, toolbar_selector: toolbar_selector)
8+
end
9+
410
let(:author) { Author.create!(email: 'some_email@example.com', name: 'John Doe', age: 30) }
5-
let!(:post) { Post.create!(title: 'Test', author: author, description: 'Some content...') }
11+
let!(:post) { Post.create!(title: 'Test', author: author, description: '') }
612

713
context 'with a Quill editor' do
8-
it 'initialize the editor' do
9-
visit "/admin/posts/#{post.id}/edit"
14+
let(:editor) { lookup_editor(field: 'post_description') }
1015

11-
%w[bold italic underline link].each do |button|
12-
expect(page).to have_css(".ql-toolbar button.ql-#{button}")
13-
end
14-
expect(page).to have_css('#post_description[data-aa-quill-editor]')
15-
expect(page).to have_css('#post_description_input .ql-editor', text: 'Some content...')
16+
before do
17+
path = edit_admin_post_path(post)
18+
Admin::Posts::EditPage.new(path: path).load
1619
end
1720

18-
it 'adds some text to the description' do
19-
visit "/admin/posts/#{post.id}/edit"
21+
it 'adds some text to the description', :aggregate_failures do
22+
expect(page).to have_css('#post_description[data-aa-quill-editor]')
23+
editor << 'Some content...'
24+
%i[bold italic underline link].each do |control|
25+
expect(page).to have_css editor.control_selector(control)
26+
end
27+
expect(editor.content_element).to have_content('Some content...')
28+
expect { find('[type="submit"]').click }
29+
.to change { post.reload.description }.to '<p>Some content...</p>'
30+
end
2031

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

25-
expect(page).to have_content('was successfully updated')
26-
expect(post.reload.description).to eq '<p>Some content...more text</p>'
36+
expect(editor.content_element).to have_content('Some bold text')
37+
expect { find('[type="submit"]').click }
38+
.to change { post.reload.description }.to '<p><strong>Some bold text</strong></p>'
2739
end
2840

29-
it 'adds some bold text to the description' do
30-
visit "/admin/posts/#{post.id}/edit"
31-
32-
find('#post_description_input .ql-editor').click
33-
find('#post_description_input .ql-toolbar .ql-bold').click
34-
find('#post_description_input .ql-editor').base.send_keys('more text')
35-
find('[type="submit"]').click
41+
it 'adds some italic text to the description', :aggregate_failures do
42+
editor.toolbar_control(:italic)
43+
editor << 'Some italic text'
3644

37-
expect(post.reload.description).to eq '<p>Some content...<strong>more text</strong></p>'
45+
expect(editor.content_element).to have_content('Some italic text')
46+
expect { find('[type="submit"]').click }
47+
.to change { post.reload.description }.to '<p><em>Some italic text</em></p>'
3848
end
3949

40-
it 'adds some italic text to the description' do
41-
visit "/admin/posts/#{post.id}/edit"
50+
it 'adds some underline text to the description', :aggregate_failures do
51+
editor.toolbar_control(:underline)
52+
editor << 'Some underline text'
4253

43-
find('#post_description_input .ql-editor').click
44-
find('#post_description_input .ql-toolbar .ql-italic').click
45-
find('#post_description_input .ql-editor').base.send_keys('more text')
46-
find('[type="submit"]').click
54+
expect(editor.content_element).to have_content('Some underline text')
55+
expect { find('[type="submit"]').click }
56+
.to change { post.reload.description }.to '<p><u>Some underline text</u></p>'
57+
end
4758

48-
expect(post.reload.description).to eq '<p>Some content...<em>more text</em></p>'
59+
it 'adds a link to the description', :aggregate_failures do
60+
editor << "Just a link"
61+
editor.select_all
62+
editor.toolbar_control(:link)
63+
editor.element.find('[data-link]').send_keys("https://www.google.com", :return)
64+
65+
expect(editor.content_element).to have_content('Just a link')
66+
html = '<p><a href="Just a linkhttps://www.google.com" rel="noopener noreferrer" target="_blank">Just a link</a></p>'
67+
expect { find('[type="submit"]').click }.to change { post.reload.description }.to html
4968
end
5069
end
5170

5271
context 'with 2 Quill editors' do
53-
it 'updates some HTML content for 2 fields' do
54-
visit "/admin/posts/#{post.id}/edit"
55-
56-
find('#post_description_input .ql-editor').click
57-
find('#post_description_input .ql-toolbar .ql-bold').click
58-
find('#post_description_input .ql-editor').base.send_keys('more text')
59-
find('#post_summary_input .ql-editor').click
60-
find('#post_summary_input .ql-toolbar .ql-italic').click
61-
find('#post_summary_input .ql-editor').base.send_keys('Summary text')
72+
before do
73+
path = edit_admin_post_path(post)
74+
Admin::Posts::EditPage.new(path: path).load
75+
end
76+
77+
it 'updates some HTML content for 2 fields', :aggregate_failures do
78+
editor1 = lookup_editor(field: 'post_description')
79+
editor1.clear.toolbar_control(:bold)
80+
editor1 << "Some description"
81+
82+
editor2 = lookup_editor(field: 'post_summary')
83+
editor2.clear.toolbar_control(:italic)
84+
editor2 << "Some summary"
85+
6286
find('[type="submit"]').click
6387
post.reload
6488

65-
expect(post.description).to eq '<p>Some content...<strong>more text</strong></p>'
66-
expect(post.summary).to eq '<p><em>Summary text</em></p>'
89+
expect(post.description).to eq '<p><strong>Some description</strong></p>'
90+
expect(post.summary).to eq '<p><em>Some summary</em></p>'
6791
end
6892
end
6993

7094
context 'with a Quill editor in a nested resource' do
71-
it 'updates some HTML content of a new nested resource' do
72-
visit "/admin/authors/#{author.id}/edit"
95+
before do
96+
path = edit_admin_author_path(author)
97+
Admin::Authors::EditPage.new(path: path).load
98+
end
7399

74-
expect(page).to have_css('.posts.has_many_container .ql-editor', text: 'Some content...')
100+
it 'updates some HTML content of a new nested resource', :aggregate_failures do
75101
find('.posts.has_many_container .has_many_add').click
76102
expect(page).to have_css('.posts.has_many_container .ql-editor', count: 2)
77103

104+
editor = lookup_editor(field: 'author_posts_attributes_1_description')
105+
editor << "Some post text"
106+
78107
fill_in('author[posts_attributes][1][title]', with: 'A new post')
79-
find('#author_posts_attributes_1_description_input .ql-editor').base.send_keys('new post text')
80108
find('[type="submit"]').click
81109

82110
expect(page).to have_content('was successfully updated')
83-
expect(author.posts.last.description).to eq '<p>new post text</p>'
111+
expect(author.posts.last.description).to eq '<p>Some post text</p>'
84112
end
85113
end
86114
end

0 commit comments

Comments
 (0)