cypress-on-rails 1.18.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/claude-code-review.yml +57 -0
- data/.github/workflows/claude.yml +50 -0
- data/CHANGELOG.md +319 -98
- data/README.md +93 -1
- data/RELEASING.md +200 -0
- data/Rakefile +1 -4
- data/cypress-on-rails.gemspec +1 -0
- data/docs/BEST_PRACTICES.md +678 -0
- data/docs/DX_IMPROVEMENTS.md +163 -0
- data/docs/PLAYWRIGHT_GUIDE.md +554 -0
- data/docs/RELEASE.md +124 -0
- data/docs/TROUBLESHOOTING.md +351 -0
- data/docs/VCR_GUIDE.md +499 -0
- data/lib/cypress_on_rails/configuration.rb +24 -0
- data/lib/cypress_on_rails/railtie.rb +7 -0
- data/lib/cypress_on_rails/server.rb +197 -0
- data/lib/cypress_on_rails/state_reset_middleware.rb +58 -0
- data/lib/cypress_on_rails/version.rb +1 -1
- data/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +12 -0
- data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_factory_bot.cy.js +2 -2
- data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_scenarios.cy.js +1 -1
- data/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js +1 -1
- data/lib/tasks/cypress.rake +33 -0
- data/rakelib/release.rake +80 -0
- data/rakelib/task_helpers.rb +23 -0
- data/rakelib/update_changelog.rake +63 -0
- metadata +31 -2
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'cypress_on_rails/configuration'
|
5
|
+
|
6
|
+
module CypressOnRails
|
7
|
+
class Server
|
8
|
+
attr_reader :host, :port, :framework, :install_folder
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
config = CypressOnRails.configuration
|
12
|
+
|
13
|
+
@framework = options[:framework] || :cypress
|
14
|
+
@host = options[:host] || config.server_host
|
15
|
+
@port = options[:port] || config.server_port || find_available_port
|
16
|
+
@port = @port.to_i if @port
|
17
|
+
@install_folder = options[:install_folder] || config.install_folder || detect_install_folder
|
18
|
+
@transactional = options.fetch(:transactional, config.transactional_server)
|
19
|
+
end
|
20
|
+
|
21
|
+
def open
|
22
|
+
start_server do
|
23
|
+
run_command(open_command, "Opening #{framework} test runner")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
start_server do
|
29
|
+
result = run_command(run_command_args, "Running #{framework} tests")
|
30
|
+
exit(result ? 0 : 1)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def init
|
35
|
+
ensure_install_folder_exists
|
36
|
+
puts "#{framework.to_s.capitalize} configuration initialized at #{install_folder}"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def detect_install_folder
|
42
|
+
# Check common locations for cypress/playwright installation
|
43
|
+
possible_folders = ['e2e', 'spec/e2e', 'spec/cypress', 'spec/playwright', 'cypress', 'playwright']
|
44
|
+
folder = possible_folders.find { |f| File.exist?(File.expand_path(f)) }
|
45
|
+
folder || 'e2e'
|
46
|
+
end
|
47
|
+
|
48
|
+
def ensure_install_folder_exists
|
49
|
+
unless File.exist?(install_folder)
|
50
|
+
puts "Creating #{install_folder} directory..."
|
51
|
+
FileUtils.mkdir_p(install_folder)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def find_available_port
|
56
|
+
server = TCPServer.new('127.0.0.1', 0)
|
57
|
+
port = server.addr[1]
|
58
|
+
server.close
|
59
|
+
port
|
60
|
+
end
|
61
|
+
|
62
|
+
def start_server(&block)
|
63
|
+
config = CypressOnRails.configuration
|
64
|
+
|
65
|
+
run_hook(config.before_server_start)
|
66
|
+
|
67
|
+
ENV['CYPRESS'] = '1'
|
68
|
+
ENV['RAILS_ENV'] = 'test'
|
69
|
+
|
70
|
+
server_pid = spawn_server
|
71
|
+
|
72
|
+
begin
|
73
|
+
wait_for_server
|
74
|
+
run_hook(config.after_server_start)
|
75
|
+
|
76
|
+
puts "Rails server started on #{base_url}"
|
77
|
+
|
78
|
+
if @transactional && defined?(ActiveRecord::Base)
|
79
|
+
ActiveRecord::Base.connection.begin_transaction(joinable: false)
|
80
|
+
run_hook(config.after_transaction_start)
|
81
|
+
end
|
82
|
+
|
83
|
+
yield
|
84
|
+
|
85
|
+
ensure
|
86
|
+
run_hook(config.before_server_stop)
|
87
|
+
|
88
|
+
if @transactional && defined?(ActiveRecord::Base)
|
89
|
+
ActiveRecord::Base.connection.rollback_transaction if ActiveRecord::Base.connection.transaction_open?
|
90
|
+
end
|
91
|
+
|
92
|
+
stop_server(server_pid)
|
93
|
+
ENV.delete('CYPRESS')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def spawn_server
|
98
|
+
rails_args = if File.exist?('bin/rails')
|
99
|
+
['bin/rails']
|
100
|
+
else
|
101
|
+
['bundle', 'exec', 'rails']
|
102
|
+
end
|
103
|
+
|
104
|
+
server_args = rails_args + ['server', '-p', port.to_s, '-b', host]
|
105
|
+
|
106
|
+
puts "Starting Rails server: #{server_args.join(' ')}"
|
107
|
+
|
108
|
+
spawn(*server_args, out: $stdout, err: $stderr)
|
109
|
+
end
|
110
|
+
|
111
|
+
def wait_for_server(timeout = 30)
|
112
|
+
Timeout.timeout(timeout) do
|
113
|
+
loop do
|
114
|
+
begin
|
115
|
+
TCPSocket.new(host, port).close
|
116
|
+
break
|
117
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
118
|
+
sleep 0.1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
rescue Timeout::Error
|
123
|
+
raise "Rails server failed to start on #{host}:#{port} after #{timeout} seconds"
|
124
|
+
end
|
125
|
+
|
126
|
+
def stop_server(pid)
|
127
|
+
if pid
|
128
|
+
puts "Stopping Rails server (PID: #{pid})"
|
129
|
+
Process.kill('TERM', pid)
|
130
|
+
Process.wait(pid)
|
131
|
+
end
|
132
|
+
rescue Errno::ESRCH
|
133
|
+
# Process already terminated
|
134
|
+
end
|
135
|
+
|
136
|
+
def base_url
|
137
|
+
"http://#{host}:#{port}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def open_command
|
141
|
+
case framework
|
142
|
+
when :cypress
|
143
|
+
if command_exists?('yarn')
|
144
|
+
['yarn', 'cypress', 'open', '--project', install_folder, '--config', "baseUrl=#{base_url}"]
|
145
|
+
elsif command_exists?('npx')
|
146
|
+
['npx', 'cypress', 'open', '--project', install_folder, '--config', "baseUrl=#{base_url}"]
|
147
|
+
else
|
148
|
+
['cypress', 'open', '--project', install_folder, '--config', "baseUrl=#{base_url}"]
|
149
|
+
end
|
150
|
+
when :playwright
|
151
|
+
if command_exists?('yarn')
|
152
|
+
['yarn', 'playwright', 'test', '--ui']
|
153
|
+
elsif command_exists?('npx')
|
154
|
+
['npx', 'playwright', 'test', '--ui']
|
155
|
+
else
|
156
|
+
['playwright', 'test', '--ui']
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def run_command_args
|
162
|
+
case framework
|
163
|
+
when :cypress
|
164
|
+
if command_exists?('yarn')
|
165
|
+
['yarn', 'cypress', 'run', '--project', install_folder, '--config', "baseUrl=#{base_url}"]
|
166
|
+
elsif command_exists?('npx')
|
167
|
+
['npx', 'cypress', 'run', '--project', install_folder, '--config', "baseUrl=#{base_url}"]
|
168
|
+
else
|
169
|
+
['cypress', 'run', '--project', install_folder, '--config', "baseUrl=#{base_url}"]
|
170
|
+
end
|
171
|
+
when :playwright
|
172
|
+
if command_exists?('yarn')
|
173
|
+
['yarn', 'playwright', 'test']
|
174
|
+
elsif command_exists?('npx')
|
175
|
+
['npx', 'playwright', 'test']
|
176
|
+
else
|
177
|
+
['playwright', 'test']
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def run_command(command_args, description)
|
183
|
+
puts "#{description}: #{command_args.join(' ')}"
|
184
|
+
system(*command_args)
|
185
|
+
end
|
186
|
+
|
187
|
+
def command_exists?(command)
|
188
|
+
system("which #{command} > /dev/null 2>&1")
|
189
|
+
end
|
190
|
+
|
191
|
+
def run_hook(hook)
|
192
|
+
if hook && hook.respond_to?(:call)
|
193
|
+
hook.call
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module CypressOnRails
|
2
|
+
class StateResetMiddleware
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
if env['PATH_INFO'] == '/__cypress__/reset_state' || env['PATH_INFO'] == '/cypress_rails_reset_state'
|
9
|
+
reset_application_state
|
10
|
+
[200, { 'Content-Type' => 'text/plain' }, ['State reset completed']]
|
11
|
+
else
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def reset_application_state
|
19
|
+
config = CypressOnRails.configuration
|
20
|
+
|
21
|
+
# Default state reset actions
|
22
|
+
if defined?(DatabaseCleaner)
|
23
|
+
DatabaseCleaner.clean_with(:truncation)
|
24
|
+
elsif defined?(ActiveRecord::Base)
|
25
|
+
connection = ActiveRecord::Base.connection
|
26
|
+
|
27
|
+
# Use disable_referential_integrity if available for safer table clearing
|
28
|
+
if connection.respond_to?(:disable_referential_integrity)
|
29
|
+
connection.disable_referential_integrity do
|
30
|
+
connection.tables.each do |table|
|
31
|
+
next if table == 'schema_migrations' || table == 'ar_internal_metadata'
|
32
|
+
connection.execute("DELETE FROM #{connection.quote_table_name(table)}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
# Fallback to regular deletion with proper table name quoting
|
37
|
+
connection.tables.each do |table|
|
38
|
+
next if table == 'schema_migrations' || table == 'ar_internal_metadata'
|
39
|
+
connection.execute("DELETE FROM #{connection.quote_table_name(table)}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Clear Rails cache
|
45
|
+
Rails.cache.clear if defined?(Rails) && Rails.cache
|
46
|
+
|
47
|
+
# Reset any class-level state
|
48
|
+
ActiveSupport::Dependencies.clear if defined?(ActiveSupport::Dependencies)
|
49
|
+
|
50
|
+
# Run after_state_reset hook after cleanup is complete
|
51
|
+
run_hook(config.after_state_reset)
|
52
|
+
end
|
53
|
+
|
54
|
+
def run_hook(hook)
|
55
|
+
hook.call if hook && hook.respond_to?(:call)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -15,6 +15,18 @@ if defined?(CypressOnRails)
|
|
15
15
|
<% unless options.experimental %># <% end %> cassette_library_dir: File.expand_path("#{__dir__}/../../<%= options.install_folder %>/<%= options.framework %>/fixtures/vcr_cassettes")
|
16
16
|
<% unless options.experimental %># <% end %> }
|
17
17
|
c.logger = Rails.logger
|
18
|
+
|
19
|
+
# Server configuration for rake tasks (cypress:open, cypress:run, playwright:open, playwright:run)
|
20
|
+
# c.server_host = 'localhost' # or use ENV['CYPRESS_RAILS_HOST']
|
21
|
+
# c.server_port = 3001 # or use ENV['CYPRESS_RAILS_PORT']
|
22
|
+
# c.transactional_server = true # Enable automatic transaction rollback between tests
|
23
|
+
|
24
|
+
# Server lifecycle hooks for rake tasks
|
25
|
+
# c.before_server_start = -> { DatabaseCleaner.clean_with(:truncation) }
|
26
|
+
# c.after_server_start = -> { puts "Test server started on port #{CypressOnRails.configuration.server_port}" }
|
27
|
+
# c.after_transaction_start = -> { Rails.application.load_seed }
|
28
|
+
# c.after_state_reset = -> { Rails.cache.clear }
|
29
|
+
# c.before_server_stop = -> { puts "Stopping test server..." }
|
18
30
|
|
19
31
|
# If you want to enable a before_request logic, such as authentication, logging, sending metrics, etc.
|
20
32
|
# Refer to https://www.rubydoc.info/gems/rack/Rack/Request for the `request` argument.
|
@@ -9,7 +9,7 @@ describe('Rails using factory bot examples', function() {
|
|
9
9
|
])
|
10
10
|
cy.visit('/')
|
11
11
|
cy.get('table').find('tbody').should(($tbody) => {
|
12
|
-
// clean should
|
12
|
+
// clean should have removed these from other tests
|
13
13
|
expect($tbody).not.to.contain('Hello World')
|
14
14
|
|
15
15
|
expect($tbody).to.contain('Good bye Mars')
|
@@ -23,7 +23,7 @@ describe('Rails using factory bot examples', function() {
|
|
23
23
|
])
|
24
24
|
cy.visit('/')
|
25
25
|
cy.get('table').find('tbody').should(($tbody) => {
|
26
|
-
// clean should
|
26
|
+
// clean should have removed these from other tests
|
27
27
|
expect($tbody).to.contain('Hello World')
|
28
28
|
expect($tbody).not.to.contain('Good bye Mars')
|
29
29
|
})
|
data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_scenarios.cy.js
CHANGED
@@ -7,7 +7,7 @@ describe('Rails using scenarios examples', function() {
|
|
7
7
|
cy.appScenario('basic')
|
8
8
|
cy.visit('/')
|
9
9
|
cy.get('table').find('tbody').should(($tbody) => {
|
10
|
-
// clean should
|
10
|
+
// clean should have removed these from other tests
|
11
11
|
expect($tbody).not.to.contain('Good bye Mars')
|
12
12
|
expect($tbody).not.to.contain('Hello World')
|
13
13
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// CypressOnRails:
|
1
|
+
// CypressOnRails: don't remove these commands
|
2
2
|
Cypress.Commands.add('appCommands', function (body) {
|
3
3
|
Object.keys(body).forEach(key => body[key] === undefined ? delete body[key] : {});
|
4
4
|
const log = Cypress.log({ name: "APP", message: body, autoEnd: false })
|
@@ -0,0 +1,33 @@
|
|
1
|
+
namespace :cypress do
|
2
|
+
desc "Open Cypress test runner UI"
|
3
|
+
task :open => :environment do
|
4
|
+
require 'cypress_on_rails/server'
|
5
|
+
CypressOnRails::Server.new.open
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Run Cypress tests in headless mode"
|
9
|
+
task :run => :environment do
|
10
|
+
require 'cypress_on_rails/server'
|
11
|
+
CypressOnRails::Server.new.run
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Initialize Cypress configuration"
|
15
|
+
task :init => :environment do
|
16
|
+
require 'cypress_on_rails/server'
|
17
|
+
CypressOnRails::Server.new.init
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :playwright do
|
22
|
+
desc "Open Playwright test runner UI"
|
23
|
+
task :open => :environment do
|
24
|
+
require 'cypress_on_rails/server'
|
25
|
+
CypressOnRails::Server.new(framework: :playwright).open
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Run Playwright tests in headless mode"
|
29
|
+
task :run => :environment do
|
30
|
+
require 'cypress_on_rails/server'
|
31
|
+
CypressOnRails::Server.new(framework: :playwright).run
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler"
|
4
|
+
require_relative "task_helpers"
|
5
|
+
|
6
|
+
class RaisingMessageHandler
|
7
|
+
def add_error(error)
|
8
|
+
raise error
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
13
|
+
|
14
|
+
desc("Releases the gem using the given version.
|
15
|
+
|
16
|
+
IMPORTANT: the gem version must be in valid rubygem format (no dashes).
|
17
|
+
|
18
|
+
This task depends on the gem-release (ruby gem) which is installed via `bundle install`
|
19
|
+
|
20
|
+
1st argument: The new version in rubygem format (no dashes). Pass no argument to
|
21
|
+
automatically perform a patch version bump.
|
22
|
+
2nd argument: Perform a dry run by passing 'true' as a second argument.
|
23
|
+
|
24
|
+
Note, accept defaults for rubygems options. Script will pause to get 2FA tokens.
|
25
|
+
|
26
|
+
Example: `rake release[2.1.0,false]`")
|
27
|
+
task :release, %i[gem_version dry_run] do |_t, args|
|
28
|
+
include CypressOnRails::TaskHelpers
|
29
|
+
|
30
|
+
# Check if there are uncommitted changes
|
31
|
+
unless `git status --porcelain`.strip.empty?
|
32
|
+
raise "You have uncommitted changes. Please commit or stash them before releasing."
|
33
|
+
end
|
34
|
+
|
35
|
+
args_hash = args.to_hash
|
36
|
+
|
37
|
+
is_dry_run = args_hash[:dry_run] == 'true'
|
38
|
+
|
39
|
+
gem_version = args_hash.fetch(:gem_version, "")
|
40
|
+
|
41
|
+
# See https://github.com/svenfuchs/gem-release
|
42
|
+
sh_in_dir(gem_root, "git pull --rebase")
|
43
|
+
sh_in_dir(gem_root, "gem bump --no-commit --file lib/cypress_on_rails/version.rb #{gem_version.strip.empty? ? '' : %(--version #{gem_version})}")
|
44
|
+
|
45
|
+
# Read the actual version from the file after bump
|
46
|
+
load File.expand_path("../lib/cypress_on_rails/version.rb", __dir__)
|
47
|
+
actual_version = CypressOnRails::VERSION
|
48
|
+
|
49
|
+
# Update Gemfile.lock files
|
50
|
+
sh_in_dir(gem_root, "bundle install")
|
51
|
+
|
52
|
+
unless is_dry_run
|
53
|
+
# Commit the version bump
|
54
|
+
sh_in_dir(gem_root, "git add lib/cypress_on_rails/version.rb")
|
55
|
+
sh_in_dir(gem_root, "git commit -m \"Release v#{actual_version}\"")
|
56
|
+
|
57
|
+
# Tag the release
|
58
|
+
sh_in_dir(gem_root, "git tag v#{actual_version}")
|
59
|
+
|
60
|
+
# Push the commit and tag
|
61
|
+
sh_in_dir(gem_root, "git push && git push --tags")
|
62
|
+
|
63
|
+
# Release the new gem version
|
64
|
+
puts "Carefully add your OTP for Rubygems. If you get an error, run 'gem release' again."
|
65
|
+
sh_in_dir(gem_root, "gem release")
|
66
|
+
else
|
67
|
+
puts "DRY RUN: Would have committed, tagged v#{actual_version}, pushed, and released gem"
|
68
|
+
end
|
69
|
+
|
70
|
+
msg = <<~MSG
|
71
|
+
Once you have successfully published, run these commands to update CHANGELOG.md:
|
72
|
+
|
73
|
+
bundle exec rake update_changelog
|
74
|
+
git commit -a -m 'Update CHANGELOG.md'
|
75
|
+
git push
|
76
|
+
MSG
|
77
|
+
puts msg
|
78
|
+
end
|
79
|
+
|
80
|
+
# rubocop:enable Metrics/BlockLength
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CypressOnRails
|
4
|
+
module TaskHelpers
|
5
|
+
# Returns the root folder of the cypress-on-rails gem
|
6
|
+
def gem_root
|
7
|
+
File.expand_path("..", __dir__)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Executes a string or an array of strings in a shell in the given directory
|
11
|
+
def sh_in_dir(dir, *shell_commands)
|
12
|
+
Dir.chdir(dir) do
|
13
|
+
# Without `with_unbundled_env`, running bundle in the child directories won't correctly
|
14
|
+
# update the Gemfile.lock
|
15
|
+
Bundler.with_unbundled_env do
|
16
|
+
shell_commands.flatten.each do |shell_command|
|
17
|
+
sh(shell_command.strip)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "English"
|
4
|
+
|
5
|
+
desc "Updates CHANGELOG.md inserting headers for the new version.
|
6
|
+
|
7
|
+
Argument: Git tag. Defaults to the latest tag."
|
8
|
+
|
9
|
+
task :update_changelog, %i[tag] do |_, args|
|
10
|
+
tag = args[:tag] || `git describe --tags --abbrev=0`.strip
|
11
|
+
|
12
|
+
# Remove 'v' prefix if present (e.g., v1.18.0 -> 1.18.0)
|
13
|
+
version = tag.start_with?('v') ? tag[1..-1] : tag
|
14
|
+
anchor = "[#{version}]"
|
15
|
+
|
16
|
+
changelog = File.read("CHANGELOG.md")
|
17
|
+
|
18
|
+
if changelog.include?(anchor)
|
19
|
+
puts "Tag #{version} is already documented in CHANGELOG.md, update manually if needed"
|
20
|
+
next
|
21
|
+
end
|
22
|
+
|
23
|
+
tag_date_output = `git show -s --format=%cs #{tag} 2>&1`
|
24
|
+
if $CHILD_STATUS.success?
|
25
|
+
tag_date = tag_date_output.split("\n").last.strip
|
26
|
+
else
|
27
|
+
abort("Failed to find tag #{tag}")
|
28
|
+
end
|
29
|
+
|
30
|
+
# After "## [Unreleased]", insert new version header
|
31
|
+
unreleased_section = "## [Unreleased]"
|
32
|
+
new_version_header = "\n\n## #{anchor} - #{tag_date}"
|
33
|
+
|
34
|
+
if changelog.include?(unreleased_section)
|
35
|
+
changelog.sub!(unreleased_section, "#{unreleased_section}#{new_version_header}")
|
36
|
+
else
|
37
|
+
abort("Could not find '## [Unreleased]' section in CHANGELOG.md")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Find and update version comparison links at the bottom
|
41
|
+
# Pattern: [1.18.0]: https://github.com/shakacode/cypress-playwright-on-rails/compare/v1.17.0...v1.18.0
|
42
|
+
compare_link_prefix = "https://github.com/shakacode/cypress-playwright-on-rails/compare"
|
43
|
+
|
44
|
+
# Find the last version link to determine the previous version
|
45
|
+
last_version_match = changelog.match(/\[(\d+\.\d+\.\d+(?:\.\w+)?)\]:.*?compare\/v(\d+\.\d+\.\d+(?:\.\w+)?)\.\.\.v(\d+\.\d+\.\d+(?:\.\w+)?)/)
|
46
|
+
|
47
|
+
if last_version_match
|
48
|
+
last_version = last_version_match[1]
|
49
|
+
# Add new version link at the top of the version list
|
50
|
+
new_link = "#{anchor}: #{compare_link_prefix}/v#{last_version}...v#{version}"
|
51
|
+
# Insert after the "<!-- Version diff reference list -->" comment
|
52
|
+
changelog.sub!("<!-- Version diff reference list -->", "<!-- Version diff reference list -->\n#{new_link}")
|
53
|
+
else
|
54
|
+
puts "Warning: Could not find version comparison links. You may need to add the link manually."
|
55
|
+
end
|
56
|
+
|
57
|
+
File.write("CHANGELOG.md", changelog)
|
58
|
+
puts "Updated CHANGELOG.md with an entry for #{version}"
|
59
|
+
puts "\nNext steps:"
|
60
|
+
puts "1. Edit CHANGELOG.md to add release notes under the [#{version}] section"
|
61
|
+
puts "2. Move content from [Unreleased] to [#{version}] if applicable"
|
62
|
+
puts "3. Review and commit the changes"
|
63
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cypress-on-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- miceportal team
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: gem-release
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: Integrates cypress with rails or rack applications
|
98
112
|
email:
|
99
113
|
- info@miceportal.de
|
@@ -103,6 +117,8 @@ extensions: []
|
|
103
117
|
extra_rdoc_files: []
|
104
118
|
files:
|
105
119
|
- ".github/FUNDING.yml"
|
120
|
+
- ".github/workflows/claude-code-review.yml"
|
121
|
+
- ".github/workflows/claude.yml"
|
106
122
|
- ".github/workflows/ruby.yml"
|
107
123
|
- ".gitignore"
|
108
124
|
- ".rspec"
|
@@ -110,8 +126,15 @@ files:
|
|
110
126
|
- Gemfile
|
111
127
|
- LICENSE
|
112
128
|
- README.md
|
129
|
+
- RELEASING.md
|
113
130
|
- Rakefile
|
114
131
|
- cypress-on-rails.gemspec
|
132
|
+
- docs/BEST_PRACTICES.md
|
133
|
+
- docs/DX_IMPROVEMENTS.md
|
134
|
+
- docs/PLAYWRIGHT_GUIDE.md
|
135
|
+
- docs/RELEASE.md
|
136
|
+
- docs/TROUBLESHOOTING.md
|
137
|
+
- docs/VCR_GUIDE.md
|
115
138
|
- docs/authentication.md
|
116
139
|
- docs/factory_bot_associations.md
|
117
140
|
- lib/cypress-on-rails.rb
|
@@ -124,8 +147,10 @@ files:
|
|
124
147
|
- lib/cypress_on_rails/middleware.rb
|
125
148
|
- lib/cypress_on_rails/middleware_config.rb
|
126
149
|
- lib/cypress_on_rails/railtie.rb
|
150
|
+
- lib/cypress_on_rails/server.rb
|
127
151
|
- lib/cypress_on_rails/simple_rails_factory.rb
|
128
152
|
- lib/cypress_on_rails/smart_factory_wrapper.rb
|
153
|
+
- lib/cypress_on_rails/state_reset_middleware.rb
|
129
154
|
- lib/cypress_on_rails/vcr/insert_eject_middleware.rb
|
130
155
|
- lib/cypress_on_rails/vcr/middleware_helpers.rb
|
131
156
|
- lib/cypress_on_rails/vcr/use_cassette_middleware.rb
|
@@ -153,10 +178,14 @@ files:
|
|
153
178
|
- lib/generators/cypress_on_rails/templates/spec/playwright/e2e/rails_examples/using_scenarios.spec.js
|
154
179
|
- lib/generators/cypress_on_rails/templates/spec/playwright/support/index.js.erb
|
155
180
|
- lib/generators/cypress_on_rails/templates/spec/playwright/support/on-rails.js
|
181
|
+
- lib/tasks/cypress.rake
|
156
182
|
- plugin/.gitignore
|
157
183
|
- plugin/cypress/plugins/index.js
|
158
184
|
- plugin/package.json
|
159
185
|
- plugin/support/index.js
|
186
|
+
- rakelib/release.rake
|
187
|
+
- rakelib/task_helpers.rb
|
188
|
+
- rakelib/update_changelog.rake
|
160
189
|
- spec/cypress_on_rails/command_executor/e2e_helper.rb
|
161
190
|
- spec/cypress_on_rails/command_executor/test_command.rb
|
162
191
|
- spec/cypress_on_rails/command_executor/test_command_with_options.rb
|
@@ -405,7 +434,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
405
434
|
- !ruby/object:Gem::Version
|
406
435
|
version: '0'
|
407
436
|
requirements: []
|
408
|
-
rubygems_version: 3.6.
|
437
|
+
rubygems_version: 3.6.7
|
409
438
|
specification_version: 4
|
410
439
|
summary: Integrates cypress with rails or rack applications
|
411
440
|
test_files: []
|