rolemodel-rails 0.26.0 → 1.1.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/README.md +15 -4
- data/lib/generators/rolemodel/all_generator.rb +2 -1
- data/lib/generators/rolemodel/editors/editors_generator.rb +1 -1
- data/lib/generators/rolemodel/github/README.md +14 -17
- data/lib/generators/rolemodel/github/USAGE +4 -1
- data/lib/generators/rolemodel/github/github_generator.rb +24 -18
- data/lib/generators/rolemodel/github/templates/CODEOWNERS +8 -0
- data/lib/generators/rolemodel/github/templates/dependabot.yml +87 -0
- data/lib/generators/rolemodel/github/templates/instructions +1 -0
- data/lib/generators/rolemodel/github/templates/pull_request_template.md +18 -0
- data/lib/generators/rolemodel/github/templates/workflows/ci.yml.tt +81 -0
- data/lib/generators/rolemodel/good_job/good_job_generator.rb +1 -1
- data/lib/generators/rolemodel/heroku/heroku_generator.rb +1 -1
- data/lib/generators/rolemodel/kaminari/kaminari_generator.rb +1 -1
- data/lib/generators/rolemodel/linters/all_generator.rb +1 -1
- data/lib/generators/rolemodel/linters/eslint/eslint_generator.rb +1 -1
- data/lib/generators/rolemodel/linters/rubocop/rubocop_generator.rb +1 -1
- data/lib/generators/rolemodel/lograge/lograge_generator.rb +1 -1
- data/lib/generators/rolemodel/mailers/mailers_generator.rb +1 -1
- data/lib/generators/rolemodel/mcp/README.md +13 -0
- data/lib/generators/rolemodel/mcp/USAGE +8 -0
- data/lib/generators/rolemodel/mcp/mcp_generator.rb +110 -0
- data/lib/generators/rolemodel/mcp/templates/app/assets/stylesheets/components/doorkeeper.css +140 -0
- data/lib/generators/rolemodel/mcp/templates/app/controllers/doorkeeper/base_controller.rb +7 -0
- data/lib/generators/rolemodel/mcp/templates/app/controllers/mcp_controller.rb.tt +91 -0
- data/lib/generators/rolemodel/mcp/templates/app/controllers/oauth_registrations_controller.rb +46 -0
- data/lib/generators/rolemodel/mcp/templates/app/controllers/well_known_controller.rb +39 -0
- data/lib/generators/rolemodel/mcp/templates/app/mcp/prompts/sample.rb +36 -0
- data/lib/generators/rolemodel/mcp/templates/app/mcp/resources/controller.rb +57 -0
- data/lib/generators/rolemodel/mcp/templates/app/mcp/resources/docs/SAMPLE_DOC.md +4 -0
- data/lib/generators/rolemodel/mcp/templates/app/mcp/resources/docs_controller.rb +46 -0
- data/lib/generators/rolemodel/mcp/templates/app/mcp/tools/sample.rb +42 -0
- data/lib/generators/rolemodel/mcp/templates/app/views/doorkeeper/authorizations/error.html.slim.tt +13 -0
- data/lib/generators/rolemodel/mcp/templates/app/views/doorkeeper/authorizations/new.html.slim.tt +41 -0
- data/lib/generators/rolemodel/mcp/templates/app/views/layouts/doorkeeper.html.slim +7 -0
- data/lib/generators/rolemodel/mcp/templates/config/initializers/doorkeeper.rb +537 -0
- data/lib/generators/rolemodel/mcp/templates/spec/mcp/prompts/sample_spec.rb +15 -0
- data/lib/generators/rolemodel/mcp/templates/spec/mcp/resources/controller_spec.rb +16 -0
- data/lib/generators/rolemodel/mcp/templates/spec/mcp/resources/docs_controller_spec.rb +55 -0
- data/lib/generators/rolemodel/mcp/templates/spec/mcp/tools/sample_spec.rb +15 -0
- data/lib/generators/rolemodel/mcp/templates/spec/requests/mcp_controller_spec.rb +84 -0
- data/lib/generators/rolemodel/mcp/templates/spec/requests/oauth_registrations_controller_spec.rb +62 -0
- data/lib/generators/rolemodel/mcp/templates/spec/requests/well_known_controller_spec.rb +30 -0
- data/lib/generators/rolemodel/optics/all_generator.rb +1 -1
- data/lib/generators/rolemodel/optics/base/base_generator.rb +2 -2
- data/lib/generators/rolemodel/optics/icons/icons_generator.rb +1 -1
- data/lib/generators/rolemodel/react/react_generator.rb +1 -1
- data/lib/generators/rolemodel/readme/readme_generator.rb +1 -1
- data/lib/generators/rolemodel/saas/all_generator.rb +1 -1
- data/lib/generators/rolemodel/saas/devise/devise_generator.rb +1 -1
- data/lib/generators/rolemodel/semaphore/semaphore_generator.rb +1 -1
- data/lib/generators/rolemodel/simple_form/simple_form_generator.rb +1 -1
- data/lib/generators/rolemodel/slim/slim_generator.rb +1 -1
- data/lib/generators/rolemodel/soft_destroyable/soft_destroyable_generator.rb +1 -1
- data/lib/generators/rolemodel/source_map/source_map_generator.rb +1 -1
- data/lib/generators/rolemodel/tailored_select/tailored_select_generator.rb +1 -1
- data/lib/generators/rolemodel/testing/all_generator.rb +1 -1
- data/lib/generators/rolemodel/testing/factory_bot/factory_bot_generator.rb +1 -1
- data/lib/generators/rolemodel/testing/jasmine_playwright/jasmine_playwright_generator.rb +1 -1
- data/lib/generators/rolemodel/testing/parallel_tests/parallel_tests_generator.rb +1 -1
- data/lib/generators/rolemodel/testing/rspec/rspec_generator.rb +1 -2
- data/lib/generators/rolemodel/testing/rspec/templates/rails_helper.rb +4 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/capybara_drivers.rb +0 -2
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/capybara_helper.rb +0 -46
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/playwright_helper.rb +0 -60
- data/lib/generators/rolemodel/testing/test_prof/test_prof_generator.rb +1 -1
- data/lib/generators/rolemodel/testing/vitest/vitest_generator.rb +1 -1
- data/lib/generators/rolemodel/ui_components/all_generator.rb +1 -1
- data/lib/generators/rolemodel/ui_components/flash/flash_generator.rb +1 -1
- data/lib/generators/rolemodel/ui_components/modals/modals_generator.rb +1 -1
- data/lib/generators/rolemodel/ui_components/navbar/navbar_generator.rb +1 -1
- data/lib/generators/rolemodel/webpack/webpack_generator.rb +1 -1
- data/lib/rolemodel/engine.rb +3 -1
- data/lib/rolemodel/generator_base.rb +17 -0
- data/lib/rolemodel/version.rb +1 -1
- data/lib/rolemodel-rails.rb +2 -0
- metadata +32 -7
- data/lib/generators/rolemodel/base_generator.rb +0 -14
- data/lib/generators/templates/generator/%filename%.rb.tt +0 -11
- data/lib/generators/templates/generator/README.md.tt +0 -11
- data/lib/generators/templates/generator/USAGE.tt +0 -5
- data/lib/generators/templates/generator_spec/%filename%_spec.rb.tt +0 -5
- /data/lib/{generators/rolemodel → rolemodel}/replace_content_helper.rb +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'MCPController', type: :request do
|
|
6
|
+
let(:user) { create(:user, name: 'Jane Smith', active: true, employee: true) }
|
|
7
|
+
let(:application) do
|
|
8
|
+
Doorkeeper::Application.create!(
|
|
9
|
+
name: 'MCP Test Client',
|
|
10
|
+
redirect_uri: 'https://example.com/callback',
|
|
11
|
+
scopes: 'mcp',
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe 'POST /mcp' do
|
|
16
|
+
let(:token) do
|
|
17
|
+
Doorkeeper::AccessToken.create!(
|
|
18
|
+
application: application,
|
|
19
|
+
resource_owner_id: user.id,
|
|
20
|
+
scopes: 'mcp',
|
|
21
|
+
expires_in: 2.hours.to_i,
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
let(:initialize_request) do
|
|
26
|
+
{
|
|
27
|
+
jsonrpc: '2.0',
|
|
28
|
+
id: 1,
|
|
29
|
+
method: 'initialize',
|
|
30
|
+
params: {
|
|
31
|
+
protocolVersion: '2025-11-25',
|
|
32
|
+
capabilities: {},
|
|
33
|
+
clientInfo: {
|
|
34
|
+
name: 'rspec',
|
|
35
|
+
version: '1.0',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
let(:headers) do
|
|
42
|
+
{
|
|
43
|
+
'CONTENT_TYPE' => 'application/json',
|
|
44
|
+
'ACCEPT' => 'application/json, text/event-stream',
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
let(:authorized_headers) do
|
|
49
|
+
headers.merge('Authorization' => "Bearer #{token.token}")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'returns unauthorized when no bearer token is provided' do
|
|
53
|
+
post '/mcp', params: initialize_request.to_json, headers: headers
|
|
54
|
+
|
|
55
|
+
expect(response).to have_http_status(:unauthorized)
|
|
56
|
+
expect(response.headers['WWW-Authenticate']).to include('resource_metadata=')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns forbidden when token does not include mcp scope' do
|
|
60
|
+
token = Doorkeeper::AccessToken.create!(
|
|
61
|
+
application: application,
|
|
62
|
+
resource_owner_id: user.id,
|
|
63
|
+
scopes: 'other',
|
|
64
|
+
expires_in: 2.hours.to_i,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
post '/mcp',
|
|
68
|
+
params: initialize_request.to_json,
|
|
69
|
+
headers: headers.merge('Authorization' => "Bearer #{token.token}")
|
|
70
|
+
|
|
71
|
+
expect(response).to have_http_status(:forbidden)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'returns initialize response for a valid bearer token' do
|
|
75
|
+
post '/mcp',
|
|
76
|
+
params: initialize_request.to_json,
|
|
77
|
+
headers: authorized_headers
|
|
78
|
+
|
|
79
|
+
expect(response).to have_http_status(:ok)
|
|
80
|
+
expect(response.parsed_body['result']).to be_present
|
|
81
|
+
expect(response.parsed_body['result']['capabilities']).to include('tools')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/generators/rolemodel/mcp/templates/spec/requests/oauth_registrations_controller_spec.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'OauthRegistrationsController', type: :request do
|
|
6
|
+
describe 'POST /oauth/register' do
|
|
7
|
+
let(:params) do
|
|
8
|
+
{
|
|
9
|
+
client_name: 'GitHub Copilot',
|
|
10
|
+
redirect_uris: ['http://localhost:12345/callback'],
|
|
11
|
+
grant_types: ['authorization_code'],
|
|
12
|
+
response_types: ['code'],
|
|
13
|
+
token_endpoint_auth_method: 'none',
|
|
14
|
+
scope: 'mcp',
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'creates an OAuth application and returns client_id' do
|
|
19
|
+
expect { post '/oauth/register', params: params, as: :json }
|
|
20
|
+
.to change(Doorkeeper::Application, :count).by(1)
|
|
21
|
+
|
|
22
|
+
expect(response).to have_http_status(:created)
|
|
23
|
+
body = response.parsed_body
|
|
24
|
+
expect(body['client_id']).to be_present
|
|
25
|
+
expect(body['client_name']).to eq('GitHub Copilot')
|
|
26
|
+
expect(body['redirect_uris']).to eq(['http://localhost:12345/callback'])
|
|
27
|
+
expect(body['token_endpoint_auth_method']).to eq('none')
|
|
28
|
+
expect(body).not_to have_key('client_secret')
|
|
29
|
+
|
|
30
|
+
app = Doorkeeper::Application.last
|
|
31
|
+
expect(app.name).to eq('GitHub Copilot')
|
|
32
|
+
expect(app.redirect_uri).to eq('http://localhost:12345/callback')
|
|
33
|
+
expect(app.scopes).to contain_exactly('mcp')
|
|
34
|
+
expect(app).not_to be_confidential
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'returns bad_request when redirect_uris is missing' do
|
|
38
|
+
post '/oauth/register', params: { client_name: 'Test' }, as: :json
|
|
39
|
+
|
|
40
|
+
expect(response).to have_http_status(:bad_request)
|
|
41
|
+
expect(response.parsed_body['error']).to eq('invalid_client_metadata')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'creates a confidential client when token_endpoint_auth_method is not none' do
|
|
45
|
+
params[:token_endpoint_auth_method] = 'client_secret_basic'
|
|
46
|
+
post '/oauth/register', params: params, as: :json
|
|
47
|
+
|
|
48
|
+
expect(response).to have_http_status(:created)
|
|
49
|
+
body = response.parsed_body
|
|
50
|
+
expect(body['client_secret']).to be_present
|
|
51
|
+
expect(body['token_endpoint_auth_method']).to eq('client_secret_basic')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'allows loopback redirect URIs for native clients' do
|
|
55
|
+
params[:redirect_uris] = ['http://127.0.0.1:33418/']
|
|
56
|
+
post '/oauth/register', params: params, as: :json
|
|
57
|
+
|
|
58
|
+
expect(response).to have_http_status(:created)
|
|
59
|
+
expect(response.parsed_body['redirect_uris']).to eq(['http://127.0.0.1:33418/'])
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'WellKnownController', type: :request do
|
|
6
|
+
describe 'GET /.well-known/oauth-protected-resource' do
|
|
7
|
+
it 'returns the MCP resource and authorization server' do
|
|
8
|
+
get '/.well-known/oauth-protected-resource'
|
|
9
|
+
|
|
10
|
+
expect(response).to have_http_status(:ok)
|
|
11
|
+
body = response.parsed_body
|
|
12
|
+
expect(body['resource']).to end_with('/mcp')
|
|
13
|
+
expect(body['authorization_servers']).to be_an(Array)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'GET /.well-known/oauth-authorization-server' do
|
|
18
|
+
it 'returns authorization server metadata with registration_endpoint' do
|
|
19
|
+
get '/.well-known/oauth-authorization-server'
|
|
20
|
+
|
|
21
|
+
expect(response).to have_http_status(:ok)
|
|
22
|
+
body = response.parsed_body
|
|
23
|
+
expect(body['registration_endpoint']).to end_with('/oauth/register')
|
|
24
|
+
expect(body['authorization_endpoint']).to end_with('/oauth/authorize')
|
|
25
|
+
expect(body['token_endpoint']).to end_with('/oauth/token')
|
|
26
|
+
expect(body['code_challenge_methods_supported']).to include('S256')
|
|
27
|
+
expect(body['scopes_supported']).to include('mcp')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Rolemodel
|
|
2
2
|
module Optics
|
|
3
|
-
class BaseGenerator < Rolemodel::
|
|
3
|
+
class BaseGenerator < Rolemodel::GeneratorBase
|
|
4
4
|
source_root File.expand_path('templates', __dir__)
|
|
5
5
|
|
|
6
6
|
def add_optics_package
|
|
@@ -12,7 +12,7 @@ module Rolemodel
|
|
|
12
12
|
def copy_templates
|
|
13
13
|
say 'importing stylesheet', :green
|
|
14
14
|
|
|
15
|
-
prepend_to_file 'app/assets/stylesheets/application.
|
|
15
|
+
prepend_to_file Dir.glob('app/assets/stylesheets/application.*').first, <<~SCSS
|
|
16
16
|
@import '@rolemodel/optics/dist/css/optics';
|
|
17
17
|
SCSS
|
|
18
18
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Rolemodel
|
|
4
4
|
module Optics
|
|
5
5
|
# Generates the icon helper and icon builders for the chosen icon library
|
|
6
|
-
class IconsGenerator < Rolemodel::
|
|
6
|
+
class IconsGenerator < Rolemodel::GeneratorBase
|
|
7
7
|
SUPPORTED_LIBRARIES = HashWithIndifferentAccess.new(
|
|
8
8
|
material: 'filled, size, weight, emphasis, additional_classes, color, hover_text',
|
|
9
9
|
phosphor: 'duotone, filled, size, weight, additional_classes, color, hover_text',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Rolemodel
|
|
4
4
|
module Testing
|
|
5
|
-
class JasminePlaywrightGenerator <
|
|
5
|
+
class JasminePlaywrightGenerator < GeneratorBase
|
|
6
6
|
include ReplaceContentHelper
|
|
7
7
|
source_root File.expand_path('templates', __dir__)
|
|
8
8
|
class_option :github_package_token, type: :string, default: ENV['GITHUB_PACKAGES_TOKEN'], desc: 'GitHub Packages token with access to @rolemodel packages'
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Rolemodel
|
|
4
4
|
module Testing
|
|
5
|
-
class ParallelTestsGenerator <
|
|
5
|
+
class ParallelTestsGenerator < GeneratorBase # rubocop:disable Style/Documentation
|
|
6
6
|
source_root File.expand_path('templates', __dir__)
|
|
7
7
|
|
|
8
8
|
def install_parallel_tests
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Rolemodel
|
|
4
4
|
module Testing
|
|
5
|
-
class RspecGenerator <
|
|
5
|
+
class RspecGenerator < GeneratorBase
|
|
6
6
|
source_root File.expand_path('templates', __dir__)
|
|
7
7
|
|
|
8
8
|
def install_rspec
|
|
@@ -15,7 +15,6 @@ module Rolemodel
|
|
|
15
15
|
gem 'capybara-playwright-driver'
|
|
16
16
|
gem 'marsh_grass'
|
|
17
17
|
gem 'pry'
|
|
18
|
-
gem 'webdrivers'
|
|
19
18
|
end
|
|
20
19
|
run_bundle
|
|
21
20
|
end
|
|
@@ -9,6 +9,10 @@ abort("The Rails environment is running in production mode!") if Rails.env.produ
|
|
|
9
9
|
require 'rspec/rails'
|
|
10
10
|
# Add additional requires below this line. Rails is not loaded until this point!
|
|
11
11
|
|
|
12
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
13
|
+
inflect.acronym "MCP"
|
|
14
|
+
end
|
|
15
|
+
|
|
12
16
|
# Requires supporting ruby files with custom matchers and macros, etc, in
|
|
13
17
|
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
|
14
18
|
# run as spec files by default. This means that files in spec/support that end
|
|
@@ -1,51 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Update the link_or_button selector so that we can use `click_on` with gc-menu-item
|
|
4
|
-
Capybara.modify_selector(:link_or_button) do
|
|
5
|
-
label 'link or button'
|
|
6
|
-
|
|
7
|
-
xpath do |locator, **options|
|
|
8
|
-
%i[link button].map do |selector|
|
|
9
|
-
expression_for(selector, locator, **options)
|
|
10
|
-
end.reduce(:union)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
module LoadStateWaitingLogic
|
|
15
|
-
module_function
|
|
16
|
-
|
|
17
|
-
def add_wait_for_load_state(method_names)
|
|
18
|
-
method_names.each do |method_name|
|
|
19
|
-
define_method(method_name) do |*args, **kwargs, &block|
|
|
20
|
-
super(*args, **kwargs, &block).tap do
|
|
21
|
-
return unless CapybaraHelper.supports_javascript?
|
|
22
|
-
|
|
23
|
-
Capybara.page.driver.with_playwright_page do |page|
|
|
24
|
-
page.wait_for_load_state(state: 'networkidle')
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
module LoadStateWaiter
|
|
33
|
-
include LoadStateWaitingLogic
|
|
34
|
-
|
|
35
|
-
INTERACTIVE_METHODS = %i[choose check uncheck select fill_in].freeze
|
|
36
|
-
LoadStateWaitingLogic.add_wait_for_load_state(INTERACTIVE_METHODS)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
module ElementLoadStateWaiter
|
|
40
|
-
include LoadStateWaitingLogic
|
|
41
|
-
|
|
42
|
-
INTERACTIVE_METHODS = %i[send_keys click select].freeze
|
|
43
|
-
LoadStateWaitingLogic.add_wait_for_load_state(INTERACTIVE_METHODS)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
Capybara::Node::Actions.prepend(LoadStateWaiter)
|
|
47
|
-
Capybara::Node::Element.prepend(ElementLoadStateWaiter)
|
|
48
|
-
|
|
49
3
|
module CapybaraHelper
|
|
50
4
|
TIMEOUT = 10
|
|
51
5
|
|
|
@@ -22,64 +22,4 @@ module PlaywrightHelper
|
|
|
22
22
|
|
|
23
23
|
puts "Screenshot saved to \e[4;96m#{directory}/#{filename}.png\e[0m" if print_message
|
|
24
24
|
end
|
|
25
|
-
|
|
26
|
-
def self.scope_stack
|
|
27
|
-
@scope_stack ||= []
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def current_scope
|
|
31
|
-
PlaywrightHelper.scope_stack.last || pw_page
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def within(selector, **, &block)
|
|
35
|
-
if supports_javascript?
|
|
36
|
-
begin
|
|
37
|
-
pw_locator = if selector.is_a?(Capybara::Node::Element)
|
|
38
|
-
pw_page.locator("xpath=#{selector.path}")
|
|
39
|
-
else
|
|
40
|
-
pw_page.locator(selector)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
PlaywrightHelper.scope_stack.push(pw_locator)
|
|
44
|
-
|
|
45
|
-
super
|
|
46
|
-
ensure
|
|
47
|
-
PlaywrightHelper.scope_stack.pop
|
|
48
|
-
end
|
|
49
|
-
else
|
|
50
|
-
super
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def click_on(text = nil, **args)
|
|
55
|
-
if supports_javascript? && text.present?
|
|
56
|
-
scope = current_scope
|
|
57
|
-
locator = nil
|
|
58
|
-
|
|
59
|
-
%w[button link gc-menu-item summary].each do |tag|
|
|
60
|
-
loc = scope.get_by_role(tag).get_by_text(text)
|
|
61
|
-
loc = scope.get_by_role(tag).get_by_text(text, exact: true) if loc.count > 1
|
|
62
|
-
loc = scope.locator(tag).get_by_text(text) unless loc.count == 1
|
|
63
|
-
locator = loc if loc.count == 1
|
|
64
|
-
break if locator.present?
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
locator = scope.get_by_text(text, exact: true) if locator.blank?
|
|
68
|
-
|
|
69
|
-
raise "No element matching text: '#{text}'" if locator.count < 1
|
|
70
|
-
|
|
71
|
-
if locator.count > 1
|
|
72
|
-
raise "Multiple elements matching text: '#{text}'" unless args[:match] == :first
|
|
73
|
-
|
|
74
|
-
result = locator.first.click
|
|
75
|
-
else
|
|
76
|
-
result = locator.click
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
pw_page.wait_for_load_state(state: 'networkidle')
|
|
80
|
-
result
|
|
81
|
-
else
|
|
82
|
-
Capybara.click_on(text, **args)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
25
|
end
|
data/lib/rolemodel/engine.rb
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'rails/generators/bundle_helper'
|
|
5
|
+
require_relative 'replace_content_helper'
|
|
6
|
+
|
|
7
|
+
module Rolemodel
|
|
8
|
+
class GeneratorBase < ::Rails::Generators::Base
|
|
9
|
+
include ::Rails::Generators::BundleHelper, ReplaceContentHelper
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
# based on https://github.com/rails/rails/blob/main/railties/lib/rails/generators/app_base.rb#L713
|
|
13
|
+
def run_bundle
|
|
14
|
+
bundle_command("install --quiet", "BUNDLE_IGNORE_MESSAGES" => "1")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/rolemodel/version.rb
CHANGED