Repository: line/line-bot-sdk-ruby
Pull request #537: Run test with RBS test at runtime
Author: login: Yang-33
Created: 2025-04-22T02:08:59Z | Merged: 2025-04-25T01:29:01Z

Resolve https://github.com/line/line-bot-sdk-ruby/issues/508


Diff:
diff --git a/Rakefile b/Rakefile
index f51a3a81..bae4e60c 100644
--- a/Rakefile
+++ b/Rakefile
@@ -18,8 +18,13 @@ end
 ## Development
 
 desc "Run normal tests (exclude no_missing_require_* specs)"
-task :test_normal do
-  sh "bundle exec rspec --exclude-pattern 'spec/line/bot/line_bot_api_gem_spec.rb,spec/line/bot/line_bot_gem_spec.rb'"
+task :test_normal, [:skip_tag] do |_, args|
+  skip_tag = args[:skip_tag]
+
+  rspec_opts = []
+  rspec_opts << "--tag '~#{skip_tag}'" if skip_tag
+
+  sh "bundle exec rspec --exclude-pattern 'spec/line/bot/line_bot_api_gem_spec.rb,spec/line/bot/line_bot_gem_spec.rb' #{rspec_opts.join(' ')}"
 end
 
 desc "Test line-bot-api gem spec"
@@ -50,6 +55,30 @@ task :rbs do
   sh "bundle exec rbs -I sig validate"
 end
 
+desc "RBS type check (with test)"
+task :rbs_test do
+  Dir['lib/line/bot/v2/**/*.rb'].sort.each do |file|
+    require_relative file
+  end
+
+  line_v2_targets = ObjectSpace.each_object(Module)
+                               .map(&:name)
+                               .compact
+                               .select do |mod_name|
+    mod_name.start_with?('Line::Bot::V2::')
+  end
+
+  line_v2_targets = line_v2_targets.map { |name| "#{name}::*" }.uniq
+
+  ENV['RUBYOPT']           = '-rbundler/setup -rrbs/test/setup'
+  ENV['RBS_TEST_LOGLEVEL'] = 'error'
+  ENV['RBS_TEST_RAISE']    = 'true'
+  ENV['RBS_TEST_OPT']      = '-Isig'
+  ENV['RBS_TEST_TARGET']   = line_v2_targets.join(',')
+
+  Rake::Task[:test_normal].invoke('rbs_test:skip')
+end
+
 desc "Run rubocop"
 task :rubocop do
   sh "bundle exec rubocop"
@@ -81,5 +110,6 @@ task :ci do
   Rake::Task[:rubocop].invoke
   Rake::Task[:validate_yard_comment].invoke
   Rake::Task[:rbs].invoke
+  Rake::Task[:rbs_test].invoke
   Rake::Task[:build_test].invoke
 end
diff --git a/sig/line/bot/v2/utils.rbs b/sig/line/bot/v2/utils.rbs
index 7138fd38..f4e30685 100644
--- a/sig/line/bot/v2/utils.rbs
+++ b/sig/line/bot/v2/utils.rbs
@@ -16,7 +16,7 @@ module Line
 
         def self.hash_to_struct: (Hash[untyped, untyped]) -> ::Struct[untyped]
 
-        def self.camelize: (String | Symbol) -> String
+        def self.camelize: (String | Symbol) -> String?
       end
     end
   end
diff --git a/spec/line/bot/v2/misc_spec.rb b/spec/line/bot/v2/misc_spec.rb
index a491a1d6..9a2cba88 100644
--- a/spec/line/bot/v2/misc_spec.rb
+++ b/spec/line/bot/v2/misc_spec.rb
@@ -97,10 +97,9 @@
         let(:client) { Line::Bot::V2::ManageAudience::ApiClient.new(channel_access_token: channel_access_token) }
 
         it 'uploads a json to the audience successfully' do
-          create_audience_group_request = {
-            description: 'Test Audience',
-          }
-
+          create_audience_group_request = Line::Bot::V2::ManageAudience::CreateAudienceGroupRequest.new(
+            description: 'Test Audience'
+          )
           stub_request(:post, "https://api.line.me/v2/bot/audienceGroup/upload")
             .with(
               body: "{\"description\":\"Test Audience\"}",
@@ -165,14 +164,14 @@
               'Authorization' => "Bearer #{channel_access_token}",
             }
           )
-          .to_return(status: response_code, body: { "status" => "ready" }.to_json, headers: { 'Content-Type' => 'application/json' })
+          .to_return(status: response_code, body: { "status" => "processing" }.to_json, headers: { 'Content-Type' => 'application/json' })
 
         body, status_code, headers = client.get_message_content_transcoding_by_message_id_with_http_info(
           message_id: message_id
         )
 
         expect(status_code).to eq(200)
-        expect(body.status).to eq('ready')
+        expect(body.status).to eq('processing')
         expect(headers['content-type']).to eq('application/json')
       end
     end
@@ -536,7 +535,7 @@
       expect(body.sent_messages[0].quote_token).to eq('IStG5h1Tz7b...')
     end
 
-    it 'response - success - using hash (not recommended way)' do
+    it 'response - success - using hash (not recommended way)', rbs_test: :skip do
       stub_request(:post, "https://api.line.me/v2/bot/message/push")
         .with(
           headers: {
@@ -1581,7 +1580,7 @@
     end
 
     context 'with invalid enum values' do
-      it "doesn't raise any error" do
+      it "doesn't raise any error", rbs_test: :skip do
         liff_app = Line::Bot::V2::Liff::LiffApp.new(
           liff_id: 'liffId123',
           view: Line::Bot::V2::Liff::LiffView.new(


Reviews:
user: login: Yang-33
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T12:03:45Z
user: login: Yang-33
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T12:04:55Z
user: login: Yang-33
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T12:05:47Z
user: login: Yang-33
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T12:06:44Z
user: login: mokuzon
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T01:26:02Z

Review comments:
diff_hunk: @@ -165,14 +164,14 @@
               'Authorization' => "Bearer #{channel_access_token}",
             }
           )
-          .to_return(status: response_code, body: { "status" => "ready" }.to_json, headers: { 'Content-Type' => 'application/json' })
+          .to_return(status: response_code, body: { "status" => "processing" }.to_json, headers: { 'Content-Type' => 'application/json' })
 
         body, status_code, headers = client.get_message_content_transcoding_by_message_id_with_http_info(
           message_id: message_id
         )
 
         expect(status_code).to eq(200)
-        expect(body.status).to eq('ready')
+        expect(body.status).to eq('processing')
path: spec/line/bot/v2/misc_spec.rb
user: login: Yang-33
body: just test is wrong (RBS test detects it)
created_at: 2025-04-24T12:03:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -536,7 +535,7 @@
       expect(body.sent_messages[0].quote_token).to eq('IStG5h1Tz7b...')
     end
 
-    it 'response - success - using hash (not recommended way)' do
+    it 'response - success - using hash (not recommended way)', rbs_test: :skip do
path: spec/line/bot/v2/misc_spec.rb
user: login: Yang-33
body: skip this only in rbs test because request with only hash is unrecommended(undocumented) way. `rbs_test: :skip` is marker for this skipping.
created_at: 2025-04-24T12:04:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1581,7 +1580,7 @@
     end
 
     context 'with invalid enum values' do
-      it "doesn't raise any error" do
+      it "doesn't raise any error", rbs_test: :skip do
path: spec/line/bot/v2/misc_spec.rb
user: login: Yang-33
body: rbs test fails when unknown const value(enum) is came, because unknown value is not in definition. Thus we skip this test in rbs test
created_at: 2025-04-24T12:05:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -18,8 +18,13 @@ end
 ## Development
 
 desc "Run normal tests (exclude no_missing_require_* specs)"
-task :test_normal do
-  sh "bundle exec rspec --exclude-pattern 'spec/line/bot/line_bot_api_gem_spec.rb,spec/line/bot/line_bot_gem_spec.rb'"
+task :test_normal, [:skip_tag] do |_, args|
path: Rakefile
user: login: Yang-33
body: skip some tests **only when** special argument is used.
- just running rspec test -> not skipped
- running rspec test with rbs test -> skipped
created_at: 2025-04-24T12:06:44Z
author_association: CONTRIBUTOR

PR comments:
user: login: Yang-33
created_at: 2025-04-22T02:09:24Z
body: Many tests failed
author_association: CONTRIBUTOR
user: login: Yang-33
created_at: 2025-04-24T11:40:13Z
body: - Blocked by https://github.com/line/line-bot-sdk-ruby/pull/546
- only 2 tests failed. Let me fix at last...
    - 1 issue is resolved by https://github.com/line/line-bot-sdk-ruby/pull/547 
    - 1 issue is WIP... -> it's resolved by this change
author_association: CONTRIBUTOR
user: login: mokuzon
created_at: 2025-04-25T01:26:11Z
body: Great!
author_association: CONTRIBUTOR