test: Improve test suite setup

Этот коммит содержится в:
Mattia Roccoberton
2025-04-13 15:00:22 +02:00
родитель d19fc7ddfc
Коммит 6cbb39daad
18 изменённых файлов: 114 добавлений и 209 удалений

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

@@ -47,7 +47,6 @@ gem 'capybara'
gem 'cuprite'
gem 'rspec_junit_formatter'
gem 'rspec-rails'
gem 'rspec-retry'
gem 'simplecov', require: false
# Linters

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

@@ -44,7 +44,7 @@ ActiveAdmin.register Post do
f.input :author
f.input :title
f.input :summary, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: toolbar } } } }
f.input :description, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: toolbar } } } }
f.input :description, as: :quill_editor # using default options
f.input :category
f.input :dt
f.input :position

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

@@ -1,4 +1,5 @@
# frozen_string_literal: true
ActiveAdmin.register Tag do
permit_params :name
end

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

@@ -1,8 +1,6 @@
# frozen_string_literal: true
class Post < ApplicationRecord
# enum state: %i[available unavailable arriving]
belongs_to :author, inverse_of: :posts, autosave: true
has_one :author_profile, through: :author, source: :profile
@@ -28,12 +26,12 @@ class Post < ApplicationRecord
end
class << self
def ransackable_attributes(auth_object = nil)
%w[author_id category created_at description dt id position published summary title updated_at]
def ransackable_associations(_auth_object = nil)
%w[author author_profile post_tags tags images_attachments images_blobs]
end
def ransackable_associations(auth_object = nil)
%w[author author_profile images_attachments images_blobs post_tags tags]
def ransackable_attributes(_auth_object = nil)
%w[author_id category created_at description dt id position published title summary updated_at]
end
end
end

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

@@ -3,14 +3,12 @@
class Profile < ApplicationRecord
belongs_to :author, inverse_of: :profile, touch: true
# has_rich_text :description
# def to_s
# description
# end
def to_s
description
end
class << self
def ransackable_associations(auth_object = nil)
def ransackable_associations(_auth_object = nil)
%w[author]
end

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

@@ -1,26 +1,23 @@
require_relative 'boot'
require 'rails/all'
require 'sprockets/railtie'
Bundler.require(*Rails.groups)
module Dummy
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0 if Rails::VERSION::MAJOR == 6
config.load_defaults Rails::VERSION::STRING.to_f
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
config.active_support.deprecation = :raise
###
if Gem::Version.new(Rails.version) < Gem::Version.new('7.1')
config.active_record.legacy_connection_handling = false
end
config.active_record.legacy_connection_handling = false if Gem::Version.new(Rails.version) < Gem::Version.new('7.1')
config.before_configuration do
ActiveSupport::Cache.format_version = 7.0 if Gem::Version.new(Rails.version) > Gem::Version.new('7.0')
if Gem::Version.new(Rails.version) > Gem::Version.new('7.0')
config.before_configuration do
ActiveSupport::Cache.format_version = 7.0
end
end
end
end

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

@@ -6,7 +6,7 @@ default: &default
development:
<<: *default
database: db/development.sqlite3
schema_dump: schema_development.rb
schema_dump: schema-dev.rb
test:
<<: *default

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

@@ -1,7 +1,9 @@
ActiveSupport::Reloader.to_prepare do
Rails.application.reloader.to_prepare do
ActiveStorage::Attachment.class_eval do
def self.ransackable_attributes(auth_object = nil)
%w[blob_id created_at id name record_id record_type]
class << self
def ransackable_attributes(auth_object = nil)
%w[blob_id created_at id name record_id record_type]
end
end
end
end

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

@@ -1,99 +0,0 @@
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_06_07_053739) do
create_table "active_admin_comments", force: :cascade do |t|
t.string "namespace"
t.text "body"
t.string "resource_type"
t.integer "resource_id"
t.string "author_type"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
t.index ["namespace"], name: "index_active_admin_comments_on_namespace"
t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
end
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.integer "record_id", null: false
t.integer "blob_id", null: false
t.datetime "created_at", precision: nil, null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", precision: nil, null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "authors", force: :cascade do |t|
t.string "name"
t.integer "age"
t.string "email"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
end
create_table "post_tags", force: :cascade do |t|
t.integer "post_id"
t.integer "tag_id"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.index ["post_id"], name: "index_post_tags_on_post_id"
t.index ["tag_id"], name: "index_post_tags_on_tag_id"
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "summary"
t.text "description"
t.integer "author_id"
t.string "category"
t.datetime "dt", precision: nil
t.float "position"
t.boolean "published"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.index ["author_id"], name: "index_posts_on_author_id"
end
create_table "profiles", force: :cascade do |t|
t.text "description"
t.integer "author_id"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.index ["author_id"], name: "index_profiles_on_author_id"
end
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "post_tags", "posts"
add_foreign_key "post_tags", "tags"
add_foreign_key "posts", "authors"
add_foreign_key "profiles", "authors"
end

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

@@ -7,7 +7,8 @@ end
(11..20).each do |i|
age = 21 + 3 * (i - 10)
attrs = { name: "Author #{i}", age: age, email: "some@email#{i}.com" }
Author.find_or_create_by!(attrs) do |author|
Author.find_or_create_by!(name: "Author #{i}") do |author|
author.assign_attributes(attrs)
author.profile = Profile.new(description: "Profile description for Author #{i}") if (i % 3).zero?
end
end
@@ -19,6 +20,8 @@ tags = Tag.where.not(name: 'A test tag').pluck(:id)
title: "Post #{i}",
author_id: authors.sample,
position: rand(100),
summary: "<p><em>Summary</em> for post #{i}</p>",
description: "<p><strong>Some bold</strong> <em>Some italic</em> <u>Some underline</u> [#{i}]</p>",
created_at: Time.now - rand(3600).seconds
}
attrs[:category] = 'news' if (i % 4).zero?

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

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require_relative '../../base_page'
module Admin
module Authors
class EditPage < BasePage

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

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require_relative '../../base_page'
module Admin
module Posts
class EditPage < BasePage

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

@@ -12,4 +12,8 @@ class BasePage
def load
visit(path)
end
def lookup_editor(editor_container:)
@editor = Shared::QuillEditor.new(editor_container)
end
end

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

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

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

@@ -1,44 +1,46 @@
# frozen_string_literal: true
class QuillEditor < HtmlEditor
SELECTOR = '.ql-container'
TOOLBAR_SELECTOR = '.ql-toolbar'
module Shared
class QuillEditor < HtmlEditor
SELECTOR = '.ql-container'
TOOLBAR_SELECTOR = '.ql-toolbar'
attr_reader :toolbar, :toolbar_selector
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 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 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}"
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
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

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

@@ -2,6 +2,11 @@
require_relative 'spec_helper'
require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/page_objects")
loader.setup
ENV['RAILS_ENV'] = 'test'
require 'simplecov'
@@ -13,13 +18,8 @@ abort('The Rails environment is running in production mode!') if Rails.env.produ
require 'rspec/rails'
require 'capybara/rails'
require 'rspec/retry'
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
Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require_relative f }
# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
@@ -31,6 +31,12 @@ rescue ActiveRecord::PendingMigrationError => e
end
RSpec.configure do |config|
if Gem::Version.new(Rails.version) >= Gem::Version.new('7.1')
config.fixture_paths = [Rails.root.join('spec/fixtures')]
else
config.fixture_path = Rails.root.join('spec/fixtures')
end
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
@@ -38,8 +44,6 @@ RSpec.configure do |config|
config.use_instantiated_fixtures = false
config.render_views = false
config.default_retry_count = 2
config.before(:suite) do
intro = ('-' * 80)
intro << "\n"

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

@@ -9,10 +9,10 @@ Capybara.register_driver(:capybara_cuprite) do |app|
Capybara::Cuprite::Driver.new(
app,
window_size: [1600, 1280],
window_size: [1600, 1024],
browser_options: browser_options,
process_timeout: 20,
timeout: 20,
process_timeout: 30,
timeout: 30,
inspector: true,
headless: !ENV['CUPRITE_HEADLESS'].in?(%w[n 0 no false])
)

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

@@ -2,9 +2,9 @@
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)
selector = ["##{field}_input.quill_editor", Shared::QuillEditor::SELECTOR].join(' ')
toolbar_selector = ["##{field}_input.quill_editor", Shared::QuillEditor::TOOLBAR_SELECTOR].join(' ')
Shared::QuillEditor.new(selector: selector, toolbar_selector: toolbar_selector)
end
let(:author) { Author.create!(email: 'some_email@example.com', name: 'John Doe', age: 30) }