diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..4df4b114 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,26 @@ +name: Lint + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Run RuboCop + run: bundle exec rubocop + + - name: Check for files missing newlines + run: bundle exec rake check_newlines diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..8ddb9706 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,76 @@ +require: + - rubocop-rake + - rubocop-rspec + +AllCops: + TargetRubyVersion: 2.6 + NewCops: enable + Exclude: + - 'vendor/**/*' + - 'spec/fixtures/**/*' + - 'tmp/**/*' + - 'pkg/**/*' + - 'node_modules/**/*' + - 'specs_e2e/**/*' + - 'e2e/**/*' + +# Ensure all files end with a newline +Layout/TrailingEmptyLines: + Enabled: true + EnforcedStyle: final_newline + +# Ensure no trailing whitespace +Layout/TrailingWhitespace: + Enabled: true + +# Line length - be reasonable but not too strict +Layout/LineLength: + Max: 120 + Exclude: + - 'spec/**/*' + - 'lib/generators/**/*' + +# Allow longer blocks in specs and rake tasks +Metrics/BlockLength: + Exclude: + - 'spec/**/*' + - '**/*.rake' + - 'Rakefile' + - '*.gemspec' + +# Allow longer methods in rake tasks +Metrics/MethodLength: + Exclude: + - '**/*.rake' + - 'Rakefile' + +# String literals +Style/StringLiterals: + Enabled: true + EnforcedStyle: single_quotes + ConsistentQuotesInMultiline: true + +# Frozen string literal pragma +Style/FrozenStringLiteralComment: + Enabled: true + EnforcedStyle: always + Exclude: + - 'spec/**/*' + +# Documentation +Style/Documentation: + Enabled: false + +# Allow compact module/class definitions +Style/ClassAndModuleChildren: + Enabled: false + +# RSpec specific +RSpec/ExampleLength: + Max: 20 + +RSpec/MultipleExpectations: + Max: 5 + +RSpec/NestedGroups: + Max: 4 diff --git a/Gemfile b/Gemfile index 5321bc96..817f62a8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,2 @@ source 'http://rubygems.org' gemspec - diff --git a/RELEASING.md b/RELEASING.md index c8156a2c..15b5c46e 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -224,4 +224,4 @@ open "https://github.com/shakacode/cypress-playwright-on-rails/releases/new?tag= - Always review changes before committing - The `publish` task will run tests before releasing - Tags are created locally first, then pushed -- Failed releases can be retried after fixing issues \ No newline at end of file +- Failed releases can be retried after fixing issues diff --git a/Rakefile b/Rakefile index d19b8a05..f1bc77fb 100644 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,11 @@ -require 'bundler/gem_tasks' +# frozen_string_literal: true require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) do |t| t.pattern = 'spec/cypress_on_rails/*_spec.rb' end -task default: %w[spec build] +desc 'Run all CI checks (specs, linting, newlines)' +task ci: %i[spec lint check_newlines] + +task default: :ci diff --git a/bin/install-hooks b/bin/install-hooks new file mode 100755 index 00000000..dcf6998c --- /dev/null +++ b/bin/install-hooks @@ -0,0 +1,50 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'fileutils' + +hooks_dir = File.expand_path('../.git/hooks', __dir__) +pre_commit_hook = File.join(hooks_dir, 'pre-commit') + +# Create pre-commit hook content +hook_content = <<~HOOK + #!/bin/sh + # Pre-commit hook to run linters and check for newlines + + # Check for files missing newlines + echo "Checking for files missing newlines..." + bundle exec rake check_newlines + if [ $? -ne 0 ]; then + echo "❌ Some files are missing final newlines. Run 'bundle exec rake fix_newlines' to fix." + exit 1 + fi + + # Run RuboCop on staged Ruby files + echo "Running RuboCop on staged files..." + files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\\.(rb|rake)$') + if [ -n "$files" ]; then + bundle exec rubocop $files + if [ $? -ne 0 ]; then + echo "❌ RuboCop failed. Fix issues or run 'bundle exec rake lint:fix'" + exit 1 + fi + fi + + echo "✅ All checks passed!" +HOOK + +# Create hooks directory if it doesn't exist +FileUtils.mkdir_p(hooks_dir) + +# Write the pre-commit hook +File.write(pre_commit_hook, hook_content) + +# Make it executable +File.chmod(0o755, pre_commit_hook) + +puts '✅ Pre-commit hook installed successfully!' +puts 'The hook will:' +puts ' - Check that all files end with a newline' +puts ' - Run RuboCop on staged Ruby files' +puts '' +puts 'To skip the hook temporarily, use: git commit --no-verify' diff --git a/cypress-on-rails.gemspec b/cypress-on-rails.gemspec index a53b4c42..215ec8ed 100644 --- a/cypress-on-rails.gemspec +++ b/cypress-on-rails.gemspec @@ -1,32 +1,34 @@ -# -*- encoding: utf-8 -*- -$LOAD_PATH.push File.expand_path("../lib", __FILE__) -require "cypress_on_rails/version" +$LOAD_PATH.push File.expand_path('lib', __dir__) +require 'cypress_on_rails/version' Gem::Specification.new do |s| - s.name = "cypress-on-rails" + s.name = 'cypress-on-rails' s.version = CypressOnRails::VERSION - s.author = ["miceportal team", 'Grant Petersen-Speelman'] - s.email = ["info@miceportal.de", 'grantspeelman@gmail.com'] - s.homepage = "http://github.com/shakacode/cypress-on-rails" - s.summary = "Integrates cypress with rails or rack applications" - s.description = "Integrates cypress with rails or rack applications" + s.author = ['miceportal team', 'Grant Petersen-Speelman'] + s.email = ['info@miceportal.de', 'grantspeelman@gmail.com'] + s.homepage = 'http://github.com/shakacode/cypress-on-rails' + s.summary = 'Integrates cypress with rails or rack applications' + s.description = 'Integrates cypress with rails or rack applications' s.post_install_message = 'The CypressDev constant is being deprecated and will be completely removed and replaced with CypressOnRails.' s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {spec}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } - s.require_paths = ["lib"] + s.require_paths = ['lib'] s.add_dependency 'rack' + s.add_development_dependency 'factory_bot', '!= 6.4.5' + s.add_development_dependency 'gem-release' + s.add_development_dependency 'railties', '>= 3.2' s.add_development_dependency 'rake' s.add_development_dependency 'rspec' - s.add_development_dependency 'railties', '>= 3.2' - s.add_development_dependency 'factory_bot', '!= 6.4.5' + s.add_development_dependency 'rubocop' + s.add_development_dependency 'rubocop-rake' + s.add_development_dependency 'rubocop-rspec' s.add_development_dependency 'vcr' - s.add_development_dependency 'gem-release' s.metadata = { - "bug_tracker_uri" => "https://github.com/shakacode/cypress-on-rails/issues", - "changelog_uri" => "https://github.com/shakacode/cypress-on-rails/blob/master/CHANGELOG.md", - "documentation_uri" => "https://github.com/shakacode/cypress-on-rails/blob/master/README.md", - "homepage_uri" => "http://github.com/shakacode/cypress-on-rails", - "source_code_uri" => "http://github.com/shakacode/cypress-on-rails" -} + 'bug_tracker_uri' => 'https://github.com/shakacode/cypress-on-rails/issues', + 'changelog_uri' => 'https://github.com/shakacode/cypress-on-rails/blob/master/CHANGELOG.md', + 'documentation_uri' => 'https://github.com/shakacode/cypress-on-rails/blob/master/README.md', + 'homepage_uri' => 'http://github.com/shakacode/cypress-on-rails', + 'source_code_uri' => 'http://github.com/shakacode/cypress-on-rails', + 'rubygems_mfa_required' => 'true' + } end diff --git a/docs/BEST_PRACTICES.md b/docs/BEST_PRACTICES.md index cdd626e5..594f3eaf 100644 --- a/docs/BEST_PRACTICES.md +++ b/docs/BEST_PRACTICES.md @@ -675,4 +675,4 @@ Following these best practices will help you: - Secure your test infrastructure - Debug issues more effectively -Remember: E2E tests should focus on critical user journeys. Use unit and integration tests for comprehensive coverage of edge cases. \ No newline at end of file +Remember: E2E tests should focus on critical user journeys. Use unit and integration tests for comprehensive coverage of edge cases. diff --git a/docs/DX_IMPROVEMENTS.md b/docs/DX_IMPROVEMENTS.md index 2a4c8d80..7d351fe8 100644 --- a/docs/DX_IMPROVEMENTS.md +++ b/docs/DX_IMPROVEMENTS.md @@ -160,4 +160,4 @@ To continue improving developer experience: ## Conclusion -These documentation and feature improvements directly address the most common pain points users face. By providing comprehensive guides, troubleshooting resources, and automated solutions, we've significantly improved the developer experience for both new and existing users of cypress-playwright-on-rails. \ No newline at end of file +These documentation and feature improvements directly address the most common pain points users face. By providing comprehensive guides, troubleshooting resources, and automated solutions, we've significantly improved the developer experience for both new and existing users of cypress-playwright-on-rails. diff --git a/docs/PLAYWRIGHT_GUIDE.md b/docs/PLAYWRIGHT_GUIDE.md index 3c3184d4..c0ae40b4 100644 --- a/docs/PLAYWRIGHT_GUIDE.md +++ b/docs/PLAYWRIGHT_GUIDE.md @@ -551,4 +551,4 @@ test('debug this', async ({ page }, testInfo) => { View traces: ```bash npx playwright show-trace trace-debug-this.zip -``` \ No newline at end of file +``` diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 8205a0e6..e8c04180 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -348,4 +348,4 @@ If you encounter issues not covered here: - Your Rails version - cypress-on-rails version - Minimal reproduction steps - - Full error messages and stack traces \ No newline at end of file + - Full error messages and stack traces diff --git a/docs/VCR_GUIDE.md b/docs/VCR_GUIDE.md index 911ae489..ceac421f 100644 --- a/docs/VCR_GUIDE.md +++ b/docs/VCR_GUIDE.md @@ -496,4 +496,4 @@ Remember to: - Configure VCR appropriately for your needs - Filter sensitive data - Organize cassettes logically -- Keep cassettes up to date \ No newline at end of file +- Keep cassettes up to date diff --git a/docs/authentication.md b/docs/authentication.md index d5dc1428..303c1135 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -80,4 +80,4 @@ Examples of usage in Playwright specs: ```js await forceLogin(page, { email: 'someuser@mail.com', redirect_to: '/profile' }); -``` \ No newline at end of file +``` diff --git a/lib/cypress-on-rails.rb b/lib/cypress-on-rails.rb index ec492107..e6605865 100644 --- a/lib/cypress-on-rails.rb +++ b/lib/cypress-on-rails.rb @@ -1,6 +1,6 @@ require 'cypress_on_rails/version' require 'cypress_on_rails/configuration' -require_relative './cypress_on_rails/railtie' if defined?(Rails) +require_relative 'cypress_on_rails/railtie' if defined?(Rails) # maintain backward compatibility CypressDev = CypressOnRails unless defined?(CypressDev) diff --git a/lib/cypress/smart_factory_wrapper.rb b/lib/cypress/smart_factory_wrapper.rb index 32c2529d..7b0b1970 100644 --- a/lib/cypress/smart_factory_wrapper.rb +++ b/lib/cypress/smart_factory_wrapper.rb @@ -1,3 +1,3 @@ require 'cypress-on-rails' require 'cypress_on_rails/smart_factory_wrapper' -# for backward compatibility \ No newline at end of file +# for backward compatibility diff --git a/lib/cypress_dev/middleware.rb b/lib/cypress_dev/middleware.rb index 06d6f3f0..631377d7 100644 --- a/lib/cypress_dev/middleware.rb +++ b/lib/cypress_dev/middleware.rb @@ -1,2 +1,2 @@ -warn "cypress_dev is being deprecated, please require \"cypress_on_rails/middleware\" instead" +warn 'cypress_dev is being deprecated, please require "cypress_on_rails/middleware" instead' require 'cypress_on_rails/middleware' diff --git a/lib/cypress_dev/smart_factory_wrapper.rb b/lib/cypress_dev/smart_factory_wrapper.rb index 5105077f..1c4d96b4 100644 --- a/lib/cypress_dev/smart_factory_wrapper.rb +++ b/lib/cypress_dev/smart_factory_wrapper.rb @@ -1,2 +1,2 @@ -warn "cypress_dev is being deprecated, please require \"cypress_on_rails/smart_factory_wrapper\" instead" +warn 'cypress_dev is being deprecated, please require "cypress_on_rails/smart_factory_wrapper" instead' require 'cypress_on_rails/smart_factory_wrapper' diff --git a/lib/cypress_on_rails/command_executor.rb b/lib/cypress_on_rails/command_executor.rb index 3af06059..01cc1dd9 100644 --- a/lib/cypress_on_rails/command_executor.rb +++ b/lib/cypress_on_rails/command_executor.rb @@ -3,11 +3,11 @@ module CypressOnRails # loads and evals the command files class CommandExecutor - def self.perform(file,command_options = nil) + def self.perform(file, command_options = nil) load_e2e_helper file_data = File.read(file) eval file_data, binding, file - rescue => e + rescue StandardError => e logger.error("fail to execute #{file}: #{e.message}") logger.error(e.backtrace.join("\n")) raise e @@ -20,7 +20,7 @@ def self.load_e2e_helper Kernel.require e2e_helper_file elsif File.exist?(cypress_helper_file) Kernel.require cypress_helper_file - warn "cypress_helper.rb is deprecated, please rename the file to e2e_helper.rb" + warn 'cypress_helper.rb is deprecated, please rename the file to e2e_helper.rb' else logger.warn "could not find #{e2e_helper_file} nor #{cypress_helper_file}" end diff --git a/lib/cypress_on_rails/configuration.rb b/lib/cypress_on_rails/configuration.rb index a1280526..51346d46 100644 --- a/lib/cypress_on_rails/configuration.rb +++ b/lib/cypress_on_rails/configuration.rb @@ -2,34 +2,23 @@ module CypressOnRails class Configuration - attr_accessor :api_prefix - attr_accessor :install_folder - attr_accessor :use_middleware - attr_accessor :use_vcr_middleware - attr_accessor :use_vcr_use_cassette_middleware - attr_accessor :before_request - attr_accessor :logger - attr_accessor :vcr_options - + attr_accessor :api_prefix, :install_folder, :use_middleware, :use_vcr_middleware, :use_vcr_use_cassette_middleware, + :before_request, :logger, :vcr_options, :after_server_start, :after_transaction_start, :after_state_reset, :before_server_stop, :server_port, :transactional_server + # Server hooks for managing test lifecycle attr_accessor :before_server_start - attr_accessor :after_server_start - attr_accessor :after_transaction_start - attr_accessor :after_state_reset - attr_accessor :before_server_stop - + # Server configuration attr_accessor :server_host - attr_accessor :server_port - attr_accessor :transactional_server # Attributes for backwards compatibility def cypress_folder - warn "cypress_folder is deprecated, please use install_folder" + warn 'cypress_folder is deprecated, please use install_folder' install_folder end + def cypress_folder=(v) - warn "cypress_folder= is deprecated, please use install_folder" + warn 'cypress_folder= is deprecated, please use install_folder' self.install_folder = v end @@ -37,9 +26,9 @@ def initialize reset end - alias :use_middleware? :use_middleware - alias :use_vcr_middleware? :use_vcr_middleware - alias :use_vcr_use_cassette_middleware? :use_vcr_use_cassette_middleware + alias use_middleware? use_middleware + alias use_vcr_middleware? use_vcr_middleware + alias use_vcr_use_cassette_middleware? use_vcr_use_cassette_middleware def reset self.api_prefix = '' @@ -47,26 +36,26 @@ def reset self.use_middleware = true self.use_vcr_middleware = false self.use_vcr_use_cassette_middleware = false - self.before_request = -> (request) {} + self.before_request = ->(request) {} self.logger = Logger.new(STDOUT) self.vcr_options = {} - + # Server hooks self.before_server_start = nil self.after_server_start = nil self.after_transaction_start = nil self.after_state_reset = nil self.before_server_stop = nil - + # Server configuration self.server_host = ENV.fetch('CYPRESS_RAILS_HOST', 'localhost') self.server_port = ENV.fetch('CYPRESS_RAILS_PORT', nil) self.transactional_server = true end - def tagged_logged + def tagged_logged(&block) if logger.respond_to?(:tagged) - logger.tagged('CY_DEV') { yield } + logger.tagged('CY_DEV', &block) else yield end diff --git a/lib/cypress_on_rails/middleware.rb b/lib/cypress_on_rails/middleware.rb index f5ed274f..5605e85f 100644 --- a/lib/cypress_on_rails/middleware.rb +++ b/lib/cypress_on_rails/middleware.rb @@ -19,7 +19,7 @@ def call(env) if request.path.start_with?("#{configuration.api_prefix}/__e2e__/command") configuration.tagged_logged { handle_command(request) } elsif request.path.start_with?("#{configuration.api_prefix}/__cypress__/command") - warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead." + warn '/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead.' configuration.tagged_logged { handle_command(request) } else @app.call(env) @@ -31,11 +31,11 @@ def call(env) Command = Struct.new(:name, :options, :install_folder) do # @return [Array] def self.from_body(body, configuration) - if body.is_a?(Array) - command_params = body - else - command_params = [body] - end + command_params = if body.is_a?(Array) + body + else + [body] + end command_params.map do |params| new(params.fetch('name'), params['options'], configuration.install_folder) end @@ -55,7 +55,7 @@ def handle_command(req) body = JSON.parse(req.body.read) logger.info "handle_command: #{body}" commands = Command.from_body(body, configuration) - missing_command = commands.find {|command| !@file.exist?(command.file_path) } + missing_command = commands.find { |command| !@file.exist?(command.file_path) } if missing_command.nil? begin @@ -64,18 +64,18 @@ def handle_command(req) begin output = results.to_json rescue NoMethodError - output = {"message" => "Cannot convert to json"}.to_json + output = { 'message' => 'Cannot convert to json' }.to_json end logger.debug "output: #{output}" - [201, {'Content-Type' => 'application/json'}, [output]] - rescue => e - output = {"message" => e.message, "class" => e.class.to_s}.to_json - [500, {'Content-Type' => 'application/json'}, [output]] + [201, { 'Content-Type' => 'application/json' }, [output]] + rescue StandardError => e + output = { 'message' => e.message, 'class' => e.class.to_s }.to_json + [500, { 'Content-Type' => 'application/json' }, [output]] end else - output = {"message" => "could not find command file: #{missing_command.file_path}"}.to_json - [404, {'Content-Type' => 'application/json'}, [output]] + output = { 'message' => "could not find command file: #{missing_command.file_path}" }.to_json + [404, { 'Content-Type' => 'application/json' }, [output]] end end end diff --git a/lib/cypress_on_rails/railtie.rb b/lib/cypress_on_rails/railtie.rb index c9fe9d99..35eea6d2 100644 --- a/lib/cypress_on_rails/railtie.rb +++ b/lib/cypress_on_rails/railtie.rb @@ -10,7 +10,7 @@ class Railtie < Rails::Railtie if CypressOnRails.configuration.use_middleware? require 'cypress_on_rails/middleware' app.middleware.use Middleware - + # Add state reset middleware for compatibility with cypress-rails require 'cypress_on_rails/state_reset_middleware' app.middleware.use StateResetMiddleware diff --git a/lib/cypress_on_rails/server.rb b/lib/cypress_on_rails/server.rb index 00168ef1..67b0c60f 100644 --- a/lib/cypress_on_rails/server.rb +++ b/lib/cypress_on_rails/server.rb @@ -9,7 +9,7 @@ class Server def initialize(options = {}) config = CypressOnRails.configuration - + @framework = options[:framework] || :cypress @host = options[:host] || config.server_host @port = options[:port] || config.server_port || find_available_port @@ -46,10 +46,10 @@ def detect_install_folder end def ensure_install_folder_exists - unless File.exist?(install_folder) - puts "Creating #{install_folder} directory..." - FileUtils.mkdir_p(install_folder) - end + return if File.exist?(install_folder) + + puts "Creating #{install_folder} directory..." + FileUtils.mkdir_p(install_folder) end def find_available_port @@ -59,36 +59,35 @@ def find_available_port port end - def start_server(&block) + def start_server config = CypressOnRails.configuration - + run_hook(config.before_server_start) - + ENV['CYPRESS'] = '1' ENV['RAILS_ENV'] = 'test' - + server_pid = spawn_server - + begin wait_for_server run_hook(config.after_server_start) - + puts "Rails server started on #{base_url}" - + if @transactional && defined?(ActiveRecord::Base) ActiveRecord::Base.connection.begin_transaction(joinable: false) run_hook(config.after_transaction_start) end - + yield - ensure run_hook(config.before_server_stop) - - if @transactional && defined?(ActiveRecord::Base) - ActiveRecord::Base.connection.rollback_transaction if ActiveRecord::Base.connection.transaction_open? + + if @transactional && defined?(ActiveRecord::Base) && ActiveRecord::Base.connection.transaction_open? + ActiveRecord::Base.connection.rollback_transaction end - + stop_server(server_pid) ENV.delete('CYPRESS') end @@ -96,10 +95,10 @@ def start_server(&block) def spawn_server rails_args = if File.exist?('bin/rails') - ['bin/rails'] - else - ['bundle', 'exec', 'rails'] - end + ['bin/rails'] + else + %w[bundle exec rails] + end server_args = rails_args + ['server', '-p', port.to_s, '-b', host] @@ -111,12 +110,10 @@ def spawn_server def wait_for_server(timeout = 30) Timeout.timeout(timeout) do loop do - begin - TCPSocket.new(host, port).close - break - rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH - sleep 0.1 - end + TCPSocket.new(host, port).close + break + rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH + sleep 0.1 end end rescue Timeout::Error @@ -170,11 +167,11 @@ def run_command_args end when :playwright if command_exists?('yarn') - ['yarn', 'playwright', 'test'] + %w[yarn playwright test] elsif command_exists?('npx') - ['npx', 'playwright', 'test'] + %w[npx playwright test] else - ['playwright', 'test'] + %w[playwright test] end end end @@ -189,9 +186,9 @@ def command_exists?(command) end def run_hook(hook) - if hook && hook.respond_to?(:call) - hook.call - end + return unless hook && hook.respond_to?(:call) + + hook.call end end -end \ No newline at end of file +end diff --git a/lib/cypress_on_rails/simple_rails_factory.rb b/lib/cypress_on_rails/simple_rails_factory.rb index 1990f263..d7dc0ce1 100644 --- a/lib/cypress_on_rails/simple_rails_factory.rb +++ b/lib/cypress_on_rails/simple_rails_factory.rb @@ -7,7 +7,7 @@ def self.create(type, *params) def self.create_list(type, amount, *params) amount.to_i.times do - create(type,*params) + create(type, *params) end end diff --git a/lib/cypress_on_rails/smart_factory_wrapper.rb b/lib/cypress_on_rails/smart_factory_wrapper.rb index b8fb8825..1c223e2a 100644 --- a/lib/cypress_on_rails/smart_factory_wrapper.rb +++ b/lib/cypress_on_rails/smart_factory_wrapper.rb @@ -50,12 +50,12 @@ def initialize(files:, factory:, always_reload: false, def create(*options) auto_reload factory_name = options.shift - if options.last.is_a?(Hash) - args = options.pop - else - args = {} - end - factory.create(factory_name,*options.map(&:to_sym),args.symbolize_keys) + args = if options.last.is_a?(Hash) + options.pop + else + {} + end + factory.create(factory_name, *options.map(&:to_sym), args.symbolize_keys) end def create_list(*args) @@ -66,11 +66,11 @@ def create_list(*args) def build(*options) auto_reload factory_name = options.shift - if options.last.is_a?(Hash) - args = options.pop - else - args = {} - end + args = if options.last.is_a?(Hash) + options.pop + else + {} + end factory.build(factory_name, *options.map(&:to_sym), args.symbolize_keys) end @@ -86,7 +86,7 @@ def reload files.each do |file| logger.debug "-- Loading: #{file}" @kernel.load(file) - end + end end private @@ -107,11 +107,12 @@ def logger end def current_latest_mtime - files.map{|file| @file_system.mtime(file) }.max + files.map { |file| @file_system.mtime(file) }.max end def auto_reload return unless should_reload? + reload end diff --git a/lib/cypress_on_rails/state_reset_middleware.rb b/lib/cypress_on_rails/state_reset_middleware.rb index f149ed7c..3caf9725 100644 --- a/lib/cypress_on_rails/state_reset_middleware.rb +++ b/lib/cypress_on_rails/state_reset_middleware.rb @@ -3,18 +3,18 @@ class StateResetMiddleware def initialize(app) @app = app end - + def call(env) - if env['PATH_INFO'] == '/__cypress__/reset_state' || env['PATH_INFO'] == '/cypress_rails_reset_state' + if ['/__cypress__/reset_state', '/cypress_rails_reset_state'].include?(env['PATH_INFO']) reset_application_state [200, { 'Content-Type' => 'text/plain' }, ['State reset completed']] else @app.call(env) end end - + private - + def reset_application_state config = CypressOnRails.configuration @@ -28,14 +28,16 @@ def reset_application_state if connection.respond_to?(:disable_referential_integrity) connection.disable_referential_integrity do connection.tables.each do |table| - next if table == 'schema_migrations' || table == 'ar_internal_metadata' + next if %w[schema_migrations ar_internal_metadata].include?(table) + connection.execute("DELETE FROM #{connection.quote_table_name(table)}") end end else # Fallback to regular deletion with proper table name quoting connection.tables.each do |table| - next if table == 'schema_migrations' || table == 'ar_internal_metadata' + next if %w[schema_migrations ar_internal_metadata].include?(table) + connection.execute("DELETE FROM #{connection.quote_table_name(table)}") end end @@ -50,9 +52,9 @@ def reset_application_state # Run after_state_reset hook after cleanup is complete run_hook(config.after_state_reset) end - + def run_hook(hook) hook.call if hook && hook.respond_to?(:call) end end -end \ No newline at end of file +end diff --git a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb index c67520bf..cd777f72 100644 --- a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +++ b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb @@ -33,11 +33,11 @@ def handle_insert(req) logger.info "vcr insert cassette: #{body}" cassette_name, options = extract_cassette_info(body) vcr.insert_cassette(cassette_name, options) - [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] + [201, { 'Content-Type' => 'application/json' }, [{ message: 'OK' }.to_json]] rescue JSON::ParserError => e - [400, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + [400, { 'Content-Type' => 'application/json' }, [{ message: e.message }.to_json]] rescue LoadError, ArgumentError => e - [500, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + [500, { 'Content-Type' => 'application/json' }, [{ message: e.message }.to_json]] end def parse_request_body(req) @@ -58,9 +58,9 @@ def handle_eject logger.info 'vcr eject cassette' vcr.eject_cassette do_first_call - [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] + [201, { 'Content-Type' => 'application/json' }, [{ message: 'OK' }.to_json]] rescue LoadError, ArgumentError => e - [500, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + [500, { 'Content-Type' => 'application/json' }, [{ message: e.message }.to_json]] end def do_first_call diff --git a/lib/generators/cypress_on_rails/install_generator.rb b/lib/generators/cypress_on_rails/install_generator.rb index 0a63f285..ae7f0db7 100644 --- a/lib/generators/cypress_on_rails/install_generator.rb +++ b/lib/generators/cypress_on_rails/install_generator.rb @@ -5,7 +5,7 @@ class InstallGenerator < Rails::Generators::Base class_option :install_folder, type: :string, default: 'e2e' class_option :install_with, type: :string, default: 'yarn' class_option :experimental, type: :boolean, default: false - source_root File.expand_path('../templates', __FILE__) + source_root File.expand_path('templates', __dir__) def install_framework directories = options.install_folder.split('/') @@ -13,9 +13,8 @@ def install_framework install_dir = "#{Dir.pwd}/#{directories.join('/')}" command = nil - packages = [] packages = if options.framework == 'cypress' - ['cypress', 'cypress-on-rails'] + %w[cypress cypress-on-rails] elsif options.framework == 'playwright' ['playwright', '@playwright/test'] end @@ -26,32 +25,32 @@ def install_framework end if command say command - fail "failed to install #{packages.join(' ')}" unless system(command) + raise "failed to install #{packages.join(' ')}" unless system(command) end if options.framework == 'cypress' - template "spec/cypress/support/index.js.erb", "#{options.install_folder}/cypress/support/index.js" - copy_file "spec/cypress/support/commands.js", "#{options.install_folder}/cypress/support/commands.js" - copy_file "spec/cypress.config.js", "#{options.install_folder}/cypress.config.js" - end - if options.framework == 'playwright' - template "spec/playwright/support/index.js.erb", "#{options.install_folder}/playwright/support/index.js" - copy_file "spec/playwright.config.js", "#{options.install_folder}/playwright.config.js" + template 'spec/cypress/support/index.js.erb', "#{options.install_folder}/cypress/support/index.js" + copy_file 'spec/cypress/support/commands.js', "#{options.install_folder}/cypress/support/commands.js" + copy_file 'spec/cypress.config.js', "#{options.install_folder}/cypress.config.js" end + return unless options.framework == 'playwright' + + template 'spec/playwright/support/index.js.erb', "#{options.install_folder}/playwright/support/index.js" + copy_file 'spec/playwright.config.js', "#{options.install_folder}/playwright.config.js" end def add_initial_files - template "config/initializers/cypress_on_rails.rb.erb", "config/initializers/cypress_on_rails.rb" - template "spec/e2e/e2e_helper.rb.erb", "#{options.install_folder}/#{options.framework}/e2e_helper.rb" + template 'config/initializers/cypress_on_rails.rb.erb', 'config/initializers/cypress_on_rails.rb' + template 'spec/e2e/e2e_helper.rb.erb', "#{options.install_folder}/#{options.framework}/e2e_helper.rb" directory 'spec/e2e/app_commands', "#{options.install_folder}/#{options.framework}/app_commands" if options.framework == 'cypress' - copy_file "spec/cypress/support/on-rails.js", "#{options.install_folder}/cypress/support/on-rails.js" + copy_file 'spec/cypress/support/on-rails.js', "#{options.install_folder}/cypress/support/on-rails.js" directory 'spec/cypress/e2e/rails_examples', "#{options.install_folder}/cypress/e2e/rails_examples" end - if options.framework == 'playwright' - copy_file "spec/playwright/support/on-rails.js", "#{options.install_folder}/playwright/support/on-rails.js" - directory 'spec/playwright/e2e/rails_examples', "#{options.install_folder}/playwright/e2e/rails_examples" - end + return unless options.framework == 'playwright' + + copy_file 'spec/playwright/support/on-rails.js', "#{options.install_folder}/playwright/support/on-rails.js" + directory 'spec/playwright/e2e/rails_examples', "#{options.install_folder}/playwright/e2e/rails_examples" end def update_files @@ -60,11 +59,11 @@ def update_files "\nimport './on-rails'", after: 'import \'./commands\'' end - if options.framework == 'playwright' - append_to_file "#{options.install_folder}/playwright/support/index.js", - "\nimport './on-rails'", - after: '// Import commands.js using ES2015 syntax:' - end + return unless options.framework == 'playwright' + + append_to_file "#{options.install_folder}/playwright/support/index.js", + "\nimport './on-rails'", + after: '// Import commands.js using ES2015 syntax:' end end end diff --git a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/activerecord_fixtures.rb b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/activerecord_fixtures.rb index cbee1703..a891e182 100644 --- a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/activerecord_fixtures.rb +++ b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/activerecord_fixtures.rb @@ -4,7 +4,7 @@ fixture_files = command_options.try(:[], 'fixtures') if defined?(ActiveRecord) - require "active_record/fixtures" + require 'active_record/fixtures' fixtures_dir ||= ActiveRecord::Tasks::DatabaseTasks.fixtures_path fixture_files ||= Dir["#{fixtures_dir}/**/*.yml"].map { |f| f[(fixtures_dir.size + 1)..-5] } @@ -12,9 +12,9 @@ logger.debug "loading fixtures: { dir: #{fixtures_dir}, files: #{fixture_files} }" ActiveRecord::FixtureSet.reset_cache ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files) - "Fixtures Done" # this gets returned + 'Fixtures Done' # this gets returned else # this else part can be removed - logger.error "Looks like activerecord_fixtures has to be modified to suite your need" + logger.error 'Looks like activerecord_fixtures has to be modified to suite your need' Post.create(title: 'MyCypressFixtures') Post.create(title: 'MyCypressFixtures2') Post.create(title: 'MyRailsFixtures') diff --git a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/clean.rb b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/clean.rb index 10c3a821..0297749b 100644 --- a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/clean.rb +++ b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/clean.rb @@ -3,7 +3,7 @@ DatabaseCleaner.strategy = :truncation DatabaseCleaner.clean else - logger.warn "add database_cleaner or update cypress/app_commands/clean.rb" + logger.warn 'add database_cleaner or update cypress/app_commands/clean.rb' Post.delete_all if defined?(Post) end @@ -15,4 +15,4 @@ WebMock.disable! if defined?(WebMock) end -Rails.logger.info "APPCLEANED" # used by log_fail.rb +Rails.logger.info 'APPCLEANED' # used by log_fail.rb diff --git a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/factory_bot.rb b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/factory_bot.rb index 73f691cf..5894657f 100644 --- a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/factory_bot.rb +++ b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/factory_bot.rb @@ -3,7 +3,7 @@ begin logger.debug "running #{factory_method}, #{factory_options}" CypressOnRails::SmartFactoryWrapper.public_send(factory_method, *factory_options) - rescue => e + rescue StandardError => e logger.error "#{e.class}: #{e.message}" logger.error e.backtrace.join("\n") logger.error "#{e.record.inspect}" if e.is_a?(ActiveRecord::RecordInvalid) diff --git a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/log_fail.rb b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/log_fail.rb index a81563cf..5a326911 100644 --- a/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/log_fail.rb +++ b/lib/generators/cypress_on_rails/templates/spec/e2e/app_commands/log_fail.rb @@ -13,14 +13,12 @@ if defined?(ActiveRecord::Base) json_result['records'] = ActiveRecord::Base.descendants.each_with_object({}) do |record_class, records| - begin - records[record_class.to_s] = record_class.limit(100).map(&:attributes) - rescue - end + records[record_class.to_s] = record_class.limit(100).map(&:attributes) + rescue StandardError end end filename = command_options.fetch('runnable_full_title', 'no title').gsub(/[^[:print:]]/, '') -File.open("#{Rails.root}/log/#{filename}.json", "w+") do |file| +File.open("#{Rails.root}/log/#{filename}.json", 'w+') do |file| file << JSON.pretty_generate(json_result) end diff --git a/lib/tasks/cypress.rake b/lib/tasks/cypress.rake index 6e7bc5ef..eff80759 100644 --- a/lib/tasks/cypress.rake +++ b/lib/tasks/cypress.rake @@ -1,33 +1,33 @@ namespace :cypress do - desc "Open Cypress test runner UI" - task :open => :environment do + desc 'Open Cypress test runner UI' + task open: :environment do require 'cypress_on_rails/server' CypressOnRails::Server.new.open end - desc "Run Cypress tests in headless mode" - task :run => :environment do + desc 'Run Cypress tests in headless mode' + task run: :environment do require 'cypress_on_rails/server' CypressOnRails::Server.new.run end - desc "Initialize Cypress configuration" - task :init => :environment do + desc 'Initialize Cypress configuration' + task init: :environment do require 'cypress_on_rails/server' CypressOnRails::Server.new.init end end namespace :playwright do - desc "Open Playwright test runner UI" - task :open => :environment do + desc 'Open Playwright test runner UI' + task open: :environment do require 'cypress_on_rails/server' CypressOnRails::Server.new(framework: :playwright).open end - desc "Run Playwright tests in headless mode" - task :run => :environment do + desc 'Run Playwright tests in headless mode' + task run: :environment do require 'cypress_on_rails/server' CypressOnRails::Server.new(framework: :playwright).run end -end \ No newline at end of file +end diff --git a/lib/tasks/update_changelog.rake b/lib/tasks/update_changelog.rake index 9a44ad0f..1740fd42 100644 --- a/lib/tasks/update_changelog.rake +++ b/lib/tasks/update_changelog.rake @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "English" +require 'English' desc "Updates CHANGELOG.md inserting headers for the new version. @@ -13,7 +13,7 @@ task :update_changelog, %i[tag] do |_, args| version = tag.start_with?('v') ? tag[1..-1] : tag anchor = "[#{version}]" - changelog = File.read("CHANGELOG.md") + changelog = File.read('CHANGELOG.md') if changelog.include?(anchor) puts "Tag #{version} is already documented in CHANGELOG.md, update manually if needed" @@ -28,7 +28,7 @@ task :update_changelog, %i[tag] do |_, args| end # After "## [Unreleased]", insert new version header - unreleased_section = "## [Unreleased]" + unreleased_section = '## [Unreleased]' new_version_header = "\n\n## #{anchor} - #{tag_date}" if changelog.include?(unreleased_section) @@ -39,25 +39,25 @@ task :update_changelog, %i[tag] do |_, args| # Find and update version comparison links at the bottom # Pattern: [1.18.0]: https://github.com/shakacode/cypress-playwright-on-rails/compare/v1.17.0...v1.18.0 - compare_link_prefix = "https://github.com/shakacode/cypress-playwright-on-rails/compare" + compare_link_prefix = 'https://github.com/shakacode/cypress-playwright-on-rails/compare' # Find the last version link to determine the previous version - last_version_match = changelog.match(/\[(\d+\.\d+\.\d+(?:\.\w+)?)\]:.*?compare\/v(\d+\.\d+\.\d+(?:\.\w+)?)\.\.\.v(\d+\.\d+\.\d+(?:\.\w+)?)/) + last_version_match = changelog.match(%r{\[(\d+\.\d+\.\d+(?:\.\w+)?)\]:.*?compare/v(\d+\.\d+\.\d+(?:\.\w+)?)\.\.\.v(\d+\.\d+\.\d+(?:\.\w+)?)}) if last_version_match last_version = last_version_match[1] # Add new version link at the top of the version list new_link = "#{anchor}: #{compare_link_prefix}/v#{last_version}...v#{version}" # Insert after the "" comment - changelog.sub!("", "\n#{new_link}") + changelog.sub!('', "\n#{new_link}") else - puts "Warning: Could not find version comparison links. You may need to add the link manually." + puts 'Warning: Could not find version comparison links. You may need to add the link manually.' end - File.write("CHANGELOG.md", changelog) + File.write('CHANGELOG.md', changelog) puts "Updated CHANGELOG.md with an entry for #{version}" puts "\nNext steps:" puts "1. Edit CHANGELOG.md to add release notes under the [#{version}] section" puts "2. Move content from [Unreleased] to [#{version}] if applicable" - puts "3. Review and commit the changes" + puts '3. Review and commit the changes' end diff --git a/rakelib/lint.rake b/rakelib/lint.rake new file mode 100644 index 00000000..a5a66eb3 --- /dev/null +++ b/rakelib/lint.rake @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +desc 'Run RuboCop' +task :rubocop do + sh 'bundle exec rubocop' +end + +desc 'Run RuboCop with auto-correct' +task 'rubocop:auto_correct' do + sh 'bundle exec rubocop -A' +end + +desc 'Run all linters' +task lint: :rubocop + +desc 'Auto-fix all linting issues' +task 'lint:fix' => 'rubocop:auto_correct' + +desc 'Ensure all files end with newline' +task :check_newlines do + files_without_newline = [] + + Dir.glob('**/*.{rb,rake,yml,yaml,md,gemspec,ru,erb,js,json}').each do |file| + next if file.include?('vendor/') || file.include?('node_modules/') || file.include?('.git/') + next if file.include?('pkg/') || file.include?('tmp/') || file.include?('coverage/') + next unless File.file?(file) + + content = File.read(file) + files_without_newline << file unless content.empty? || content.end_with?("\n") + end + + if files_without_newline.any? + puts 'Files missing final newline:' + files_without_newline.each { |f| puts " #{f}" } + exit 1 + else + puts '✓ All files end with newline' + end +end + +desc 'Fix files missing final newline' +task :fix_newlines do + fixed_files = [] + + Dir.glob('**/*.{rb,rake,yml,yaml,md,gemspec,ru,erb,js,json}').each do |file| + next if file.include?('vendor/') || file.include?('node_modules/') || file.include?('.git/') + next if file.include?('pkg/') || file.include?('tmp/') || file.include?('coverage/') + next unless File.file?(file) + + content = File.read(file) + unless content.empty? || content.end_with?("\n") + File.write(file, content + "\n") + fixed_files << file + end + end + + if fixed_files.any? + puts "Fixed #{fixed_files.length} files:" + fixed_files.each { |f| puts " #{f}" } + else + puts '✓ All files already end with newline' + end +end diff --git a/rakelib/release.rake b/rakelib/release.rake index 84fa92b9..0356dcd9 100644 --- a/rakelib/release.rake +++ b/rakelib/release.rake @@ -1,7 +1,7 @@ # frozen_string_literal: true -require "bundler" -require_relative "task_helpers" +require 'bundler' +require_relative 'task_helpers' class RaisingMessageHandler def add_error(error) @@ -9,13 +9,11 @@ class RaisingMessageHandler end end -# rubocop:disable Metrics/BlockLength - desc("Releases the gem using the given version. IMPORTANT: the gem version must be in valid rubygem format (no dashes). -This task depends on the gem-release ruby gem which is installed via `bundle install` +This task depends on the gem-release (ruby gem) which is installed via `bundle install` 1st argument: The new version in rubygem format (no dashes). Pass no argument to automatically perform a patch version bump. @@ -23,28 +21,31 @@ This task depends on the gem-release ruby gem which is installed via `bundle ins Note, accept defaults for rubygems options. Script will pause to get 2FA tokens. -Example: `rake release[1.19.0,false]`") +Example: `rake release[2.1.0,false]`") task :release, %i[gem_version dry_run] do |_t, args| include CypressOnRails::TaskHelpers # Check if there are uncommitted changes unless `git status --porcelain`.strip.empty? - raise "You have uncommitted changes. Please commit or stash them before releasing." + raise 'You have uncommitted changes. Please commit or stash them before releasing.' end args_hash = args.to_hash is_dry_run = args_hash[:dry_run] == 'true' - gem_version = args_hash.fetch(:gem_version, "") + gem_version = args_hash.fetch(:gem_version, '') # See https://github.com/svenfuchs/gem-release - sh_in_dir(gem_root, "git pull --rebase") - sh_in_dir(gem_root, "gem bump --no-commit #{gem_version.strip.empty? ? '' : %(-v #{gem_version})}") + sh_in_dir(gem_root, 'git pull --rebase') + sh_in_dir(gem_root, + "gem bump --no-commit --file lib/cypress_on_rails/version.rb #{unless gem_version.strip.empty? + %(-v #{gem_version}) + end}") # Release the new gem version puts "Carefully add your OTP for Rubygems. If you get an error, run 'gem release' again." - sh_in_dir(gem_root, "gem release") unless is_dry_run + sh_in_dir(gem_root, 'gem release') unless is_dry_run msg = <<~MSG Once you have successfully published, run these commands to update CHANGELOG.md: @@ -55,5 +56,3 @@ task :release, %i[gem_version dry_run] do |_t, args| MSG puts msg end - -# rubocop:enable Metrics/BlockLength diff --git a/rakelib/task_helpers.rb b/rakelib/task_helpers.rb index b6d67719..f5a2082d 100644 --- a/rakelib/task_helpers.rb +++ b/rakelib/task_helpers.rb @@ -4,12 +4,20 @@ module CypressOnRails module TaskHelpers # Returns the root folder of the cypress-on-rails gem def gem_root - File.expand_path("..", __dir__) + File.expand_path('..', __dir__) end # Executes a string or an array of strings in a shell in the given directory def sh_in_dir(dir, *shell_commands) - shell_commands.flatten.each { |shell_command| sh %(cd #{dir} && #{shell_command.strip}) } + Dir.chdir(dir) do + # Without `with_unbundled_env`, running bundle in the child directories won't correctly + # update the Gemfile.lock + Bundler.with_unbundled_env do + shell_commands.flatten.each do |shell_command| + sh(shell_command.strip) + end + end + end end end end diff --git a/spec/cypress_on_rails/command_executor_spec.rb b/spec/cypress_on_rails/command_executor_spec.rb index 8644a697..95a02b92 100644 --- a/spec/cypress_on_rails/command_executor_spec.rb +++ b/spec/cypress_on_rails/command_executor_spec.rb @@ -2,9 +2,10 @@ RSpec.describe CypressOnRails::CommandExecutor do describe '.perform' do - let(:folder) { "#{__dir__}/command_executor" } subject { described_class } + let(:folder) { "#{__dir__}/command_executor" } + def executor_perform(*values) subject.perform(*values) end @@ -16,18 +17,18 @@ def executor_perform(*values) it 'runs test command' do executor_perform("#{folder}/test_command.rb") - expect(DummyTest.values).to eq(%w(hello)) + expect(DummyTest.values).to eq(%w[hello]) end it 'runs test command twice' do executor_perform("#{folder}/test_command.rb") executor_perform("#{folder}/test_command.rb") - expect(DummyTest.values).to eq(%w(hello hello)) + expect(DummyTest.values).to eq(%w[hello hello]) end it 'runs command with options' do executor_perform("#{folder}/test_command_with_options.rb", 'my_string') - expect(DummyTest.values).to eq(%w(my_string)) + expect(DummyTest.values).to eq(%w[my_string]) end end end diff --git a/spec/cypress_on_rails/configuration_spec.rb b/spec/cypress_on_rails/configuration_spec.rb index f790abf7..f56fd0d2 100644 --- a/spec/cypress_on_rails/configuration_spec.rb +++ b/spec/cypress_on_rails/configuration_spec.rb @@ -7,14 +7,14 @@ expect(CypressOnRails.configuration.api_prefix).to eq('') expect(CypressOnRails.configuration.install_folder).to eq('spec/e2e') expect(CypressOnRails.configuration.use_middleware?).to eq(true) - expect(CypressOnRails.configuration.logger).to_not be_nil - expect(CypressOnRails.configuration.before_request).to_not be_nil + expect(CypressOnRails.configuration.logger).not_to be_nil + expect(CypressOnRails.configuration.before_request).not_to be_nil expect(CypressOnRails.configuration.vcr_options).to eq({}) end it 'can be configured' do my_logger = Logger.new(STDOUT) - before_request_lambda = ->(_) { return [200, {}, ['hello world']] } + before_request_lambda = ->(_) { [200, {}, ['hello world']] } CypressOnRails.configure do |config| config.api_prefix = '/api' config.install_folder = 'my/path' diff --git a/spec/cypress_on_rails/middleware_spec.rb b/spec/cypress_on_rails/middleware_spec.rb index 414b35ca..0b74064c 100644 --- a/spec/cypress_on_rails/middleware_spec.rb +++ b/spec/cypress_on_rails/middleware_spec.rb @@ -1,14 +1,13 @@ require 'cypress_on_rails/middleware' RSpec.describe CypressOnRails::Middleware do - let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } - let(:command_executor) { class_double(CypressOnRails::CommandExecutor) } - let(:file) { class_double(File) } subject { described_class.new(app, command_executor, file) } + let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } let(:env) { {} } - let(:response) { subject.call(env) } + let(:command_executor) { class_double(CypressOnRails::CommandExecutor) } + let(:file) { class_double(File) } def rack_input(json_value) StringIO.new(JSON.generate(json_value)) @@ -28,8 +27,8 @@ def rack_input(json_value) aggregate_failures do expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["[{\"id\":1,\"title\":\"some result\"}]"]]) + { 'Content-Type' => 'application/json' }, + ['[{"id":1,"title":"some result"}]']]) expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/seed.rb', nil) end end @@ -40,8 +39,8 @@ def rack_input(json_value) aggregate_failures do expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["[{\"id\":1,\"title\":\"some result\"}]"]]) + { 'Content-Type' => 'application/json' }, + ['[{"id":1,"title":"some result"}]']]) expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/seed.rb', ['my_options']) end end @@ -54,8 +53,8 @@ def rack_input(json_value) aggregate_failures do expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"Cannot convert to json\"}"]]) + { 'Content-Type' => 'application/json' }, + ['{"message":"Cannot convert to json"}']]) expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/seed.rb', nil) end end @@ -66,37 +65,37 @@ def rack_input(json_value) aggregate_failures do expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["[{\"id\":1,\"title\":\"some result\"}]"]]) + { 'Content-Type' => 'application/json' }, + ['[{"id":1,"title":"some result"}]']]) expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/seed.rb', nil) end end it 'running multiple commands' do - env['rack.input'] = rack_input([{name: 'load_user'}, - {name: 'load_sample', options: {'all' => 'true'}}]) + env['rack.input'] = rack_input([{ name: 'load_user' }, + { name: 'load_sample', options: { 'all' => 'true' } }]) allow(file).to receive(:exist?).with('spec/e2e/app_commands/load_user.rb').and_return(true) allow(file).to receive(:exist?).with('spec/e2e/app_commands/load_sample.rb').and_return(true) aggregate_failures do expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["[{\"id\":1,\"title\":\"some result\"},{\"id\":1,\"title\":\"some result\"}]"]]) + { 'Content-Type' => 'application/json' }, + ['[{"id":1,"title":"some result"},{"id":1,"title":"some result"}]']]) expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/load_user.rb', nil) - expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/load_sample.rb', {'all' => 'true'}) + expect(command_executor).to have_received(:perform).with('spec/e2e/app_commands/load_sample.rb', { 'all' => 'true' }) end end it 'running multiple commands but one missing' do - env['rack.input'] = rack_input([{name: 'load_user'}, {name: 'load_sample'}]) + env['rack.input'] = rack_input([{ name: 'load_user' }, { name: 'load_sample' }]) allow(file).to receive(:exist?).with('spec/e2e/app_commands/load_user.rb').and_return(true) allow(file).to receive(:exist?).with('spec/e2e/app_commands/load_sample.rb').and_return(false) aggregate_failures do expect(response).to eq([404, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"could not find command file: spec/e2e/app_commands/load_sample.rb\"}"]]) - expect(command_executor).to_not have_received(:perform) + { 'Content-Type' => 'application/json' }, + ['{"message":"could not find command file: spec/e2e/app_commands/load_sample.rb"}']]) + expect(command_executor).not_to have_received(:perform) end end end @@ -104,7 +103,7 @@ def rack_input(json_value) context '"Other paths"' do it 'runs app' do aggregate_failures do - %w(/ /__e2e__/login command /e2e_command /).each do |path| + %w[/ /__e2e__/login command /e2e_command /].each do |path| env['PATH_INFO'] = path response = subject.call(env) @@ -123,7 +122,7 @@ def rack_input(json_value) response = subject.call(env) - expect(response).to eq([200, {}, ["app did /test"]]) + expect(response).to eq([200, {}, ['app did /test']]) end end end diff --git a/spec/cypress_on_rails/railtie_spec.rb b/spec/cypress_on_rails/railtie_spec.rb index 88f61b3c..da4bbc23 100644 --- a/spec/cypress_on_rails/railtie_spec.rb +++ b/spec/cypress_on_rails/railtie_spec.rb @@ -1,8 +1,7 @@ require 'cypress_on_rails/railtie' module Rails - def self.env - end + def self.env; end end RSpec.describe CypressOnRails::Railtie do diff --git a/spec/cypress_on_rails/simple_rails_factory_spec.rb b/spec/cypress_on_rails/simple_rails_factory_spec.rb index c93f0be8..26ff9637 100644 --- a/spec/cypress_on_rails/simple_rails_factory_spec.rb +++ b/spec/cypress_on_rails/simple_rails_factory_spec.rb @@ -4,8 +4,7 @@ subject { CypressOnRails::SimpleRailsFactory } class AppRecord - def self.create!(*) - end + def self.create!(*); end end before { allow(AppRecord).to receive(:create!) } @@ -13,23 +12,23 @@ def self.create!(*) it do subject.create('AppRecord', { my_args: 'Hello World' }) - expect(AppRecord).to have_received(:create!).with( { my_args: 'Hello World' } ) + expect(AppRecord).to have_received(:create!).with({ my_args: 'Hello World' }) end it do subject.create('AppRecord', 'trait', { my_args: 'Hello World' }) - expect(AppRecord).to have_received(:create!).with( 'trait', { my_args: 'Hello World' } ) + expect(AppRecord).to have_received(:create!).with('trait', { my_args: 'Hello World' }) end it do subject.create('AppRecord') - expect(AppRecord).to have_received(:create!).with( { } ) + expect(AppRecord).to have_received(:create!).with({}) end it do - expect{ subject.create('UnknownRecord', { my_args: 'Hello World' }) }. - to raise_error(NameError) + expect { subject.create('UnknownRecord', { my_args: 'Hello World' }) } + .to raise_error(NameError) end end diff --git a/spec/cypress_on_rails/smart_factory_wrapper_spec.rb b/spec/cypress_on_rails/smart_factory_wrapper_spec.rb index 0f520720..7d48056a 100644 --- a/spec/cypress_on_rails/smart_factory_wrapper_spec.rb +++ b/spec/cypress_on_rails/smart_factory_wrapper_spec.rb @@ -8,11 +8,19 @@ def mtime(filename) end end + subject do + described_class.new(files: files, + factory: factory_double, + kernel: kernel_double, + file_system: file_double, + dir_system: dir_double) + end + let(:time_now) { Time.now } - let(:mtime_hash) { {'file1.rb' => time_now, 'file2.rb' => time_now } } - let(:files) { %w(file1.rb file2.rb) } + let(:mtime_hash) { { 'file1.rb' => time_now, 'file2.rb' => time_now } } + let(:files) { %w[file1.rb file2.rb] } let(:factory_double) do - class_double(FactoryBot, create: nil, create_list: nil, build: nil, build_list: nil, "definition_file_paths=": nil, reload: nil) + class_double(FactoryBot, create: nil, create_list: nil, build: nil, build_list: nil, 'definition_file_paths=': nil, reload: nil) end let(:kernel_double) { class_double(Kernel, load: true) } let(:file_double) { FileSystemDummy.new(mtime_hash) } @@ -22,47 +30,39 @@ def mtime(filename) allow(Dir).to receive(:[]).with(*files) { mtime_hash.keys } end - subject do - described_class.new(files: files, - factory: factory_double, - kernel: kernel_double, - file_system: file_double, - dir_system: dir_double) - end - it 'loads all the files on first create it' do subject.create(:user) expect(kernel_double).to have_received(:load).with('file1.rb') expect(kernel_double).to have_received(:load).with('file2.rb') end - it 'loads all the files on first create_list ' do + it 'loads all the files on first create_list' do subject.create_list(:user, 10) expect(kernel_double).to have_received(:load).with('file1.rb') expect(kernel_double).to have_received(:load).with('file2.rb') end - it 'it sends delegates create to the factory' do + it 'sends delegates create to the factory' do subject.create(:user) expect(factory_double).to have_received(:create).with(:user, {}) end - it 'it sends delegates create to the factory and symbolize keys' do - subject.create(:user, {'name' => "name"}) - expect(factory_double).to have_received(:create).with(:user, {name: 'name'}) + it 'sends delegates create to the factory and symbolize keys' do + subject.create(:user, { 'name' => 'name' }) + expect(factory_double).to have_received(:create).with(:user, { name: 'name' }) end - it 'it sends delegates create to the factory and symbolize keys with trait' do - subject.create(:user, 'trait1', {'name' => "name"}) - expect(factory_double).to have_received(:create).with(:user, :trait1, {name: 'name'}) + it 'sends delegates create to the factory and symbolize keys with trait' do + subject.create(:user, 'trait1', { 'name' => 'name' }) + expect(factory_double).to have_received(:create).with(:user, :trait1, { name: 'name' }) end - it 'it sends delegates create to the factory and symbolize keys with only trait' do + it 'sends delegates create to the factory and symbolize keys with only trait' do subject.create(:user, 'trait2') expect(factory_double).to have_received(:create).with(:user, :trait2, {}) end - it 'it sends delegates create_list to the factory' do + it 'sends delegates create_list to the factory' do subject.create_list(:note, 10) expect(factory_double).to have_received(:create_list).with(:note, 10) end @@ -73,13 +73,13 @@ def mtime(filename) end it 'delegates build to the factory and symbolize keys' do - subject.build(:user, {'name' => "name"}) - expect(factory_double).to have_received(:build).with(:user, {name: 'name'}) + subject.build(:user, { 'name' => 'name' }) + expect(factory_double).to have_received(:build).with(:user, { name: 'name' }) end it 'delegates build to the factory and symbolize keys with trait' do - subject.build(:user, 'trait1', {'name' => "name"}) - expect(factory_double).to have_received(:build).with(:user, :trait1, {name: 'name'}) + subject.build(:user, 'trait1', { 'name' => 'name' }) + expect(factory_double).to have_received(:build).with(:user, :trait1, { name: 'name' }) end it 'delegates build to the factory and symbolize keys with only trait' do @@ -99,7 +99,7 @@ def mtime(filename) expect(kernel_double).to have_received(:load).with('file2.rb').once end - it 'will reload the files if any have changed' do + it 'reloads the files if any have changed' do subject.create(:user) expect(kernel_double).to have_received(:load).with('file1.rb').once expect(kernel_double).to have_received(:load).with('file2.rb').once @@ -110,7 +110,7 @@ def mtime(filename) expect(kernel_double).to have_received(:load).with('file2.rb').twice end - it 'will reload only the files that exist' do + it 'reloads only the files that exist' do subject.always_reload = true subject.create(:user) expect(kernel_double).to have_received(:load).with('file1.rb').once @@ -122,7 +122,7 @@ def mtime(filename) expect(kernel_double).to have_received(:load).with('file2.rb').twice end - it 'will reset factory if a file has changed' do + it 'resets factory if a file has changed' do subject.create(:user) expect(factory_double).to have_received(:reload) @@ -132,7 +132,7 @@ def mtime(filename) expect(factory_double).to have_received(:reload).twice end - it 'will always reload the files enabled' do + it 'alwayses reload the files enabled' do subject.always_reload = true subject.create_list(:user, 2) subject.create(:user) diff --git a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb index 748f306c..a7d42c61 100644 --- a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb @@ -6,12 +6,11 @@ module CypressOnRails module Vcr RSpec.describe InsertEjectMiddleware do let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } - let(:vcr) { class_double(VCR, turn_on!: true, turn_off!: true, insert_cassette: true, eject_cassette: true) } - subject { described_class.new(app, vcr) } - let(:env) { {} } - let(:response) { subject.call(env) } + let(:vcr) { class_double(VCR, turn_on!: true, turn_off!: true, insert_cassette: true, eject_cassette: true) } + + subject { described_class.new(app, vcr) } def rack_input(json_value) StringIO.new(JSON.generate(json_value)) diff --git a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb index f41ff933..c6ad9d21 100644 --- a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb @@ -6,12 +6,11 @@ module CypressOnRails module Vcr RSpec.describe UseCassetteMiddleware do let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } - let(:vcr) { VCR } - subject { described_class.new(app, vcr) } - let(:env) { { 'rack.input' => rack_input([]) } } - let(:response) { subject.call(env) } + let(:vcr) { VCR } + + subject { described_class.new(app, vcr) } def rack_input(json_value) StringIO.new(JSON.generate(json_value)) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4bd0e1a1..19994e68 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -54,7 +54,7 @@ # Allows RSpec to persist some state between runs in order to support # the `--only-failures` and `--next-failure` CLI options. We recommend # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" + config.example_status_persistence_file_path = 'spec/examples.txt' # Limits the available syntax to the non-monkey patched syntax that is # recommended. For more details, see: @@ -74,7 +74,7 @@ # Use the documentation formatter for detailed output, # unless a formatter has already been configured # (e.g. via a command-line flag). - config.default_formatter = "doc" + config.default_formatter = 'doc' end # Print the 10 slowest examples and example groups at the @@ -94,7 +94,7 @@ # as the one that triggered the failure. Kernel.srand config.seed - config.before(:each) do + config.before do require 'cypress_on_rails/configuration' CypressOnRails.configure do |config| config.reset