Repository: Shopify/ruby-lsp-rails (Ruby)

Issue:
Code lens doesn't handle multiline escaped strings
We're not handling this case, but it shouldn't be hard to support it.

```ruby
test "something" \
  "otherthing" do
end
```


Discussion:

Patch:
diff --git a/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb b/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
index 1ad20443..f051a7c6 100644
--- a/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
+++ b/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
@@ -59,16 +59,26 @@ def on_command(node)
         return unless message_value == "test" && node.arguments.parts.any?
 
         first_argument = node.arguments.parts.first
-        return unless first_argument.is_a?(SyntaxTree::StringLiteral)
+
+        parts = case first_argument
+        when SyntaxTree::StringConcat
+          # We only support two lines of concatenation on test names
+          if first_argument.left.is_a?(SyntaxTree::StringLiteral) &&
+              first_argument.right.is_a?(SyntaxTree::StringLiteral)
+            [*first_argument.left.parts, *first_argument.right.parts]
+          end
+        when SyntaxTree::StringLiteral
+          first_argument.parts
+        end
 
         # The test name may be a blank string while the code is being typed
-        return if first_argument.parts.empty?
+        return if parts.nil? || parts.empty?
 
         # We can't handle interpolation yet
-        return unless first_argument.parts.all? { |part| part.is_a?(SyntaxTree::TStringContent) }
+        return unless parts.all? { |part| part.is_a?(SyntaxTree::TStringContent) }
 
-        test_name = first_argument.parts.first.value
-        return unless test_name
+        test_name = parts.map(&:value).join
+        return if test_name.empty?
 
         line_number = node.location.start_line
         command = "#{BASE_COMMAND} #{@path}:#{line_number}"


Test patch:
diff --git a/test/ruby_lsp_rails/code_lens_test.rb b/test/ruby_lsp_rails/code_lens_test.rb
index ecf3a7a7..9e9b3709 100644
--- a/test/ruby_lsp_rails/code_lens_test.rb
+++ b/test/ruby_lsp_rails/code_lens_test.rb
@@ -38,6 +38,30 @@ class Test < ActiveSupport::TestCase
         assert_match("Debug", response[5].command.title)
       end
 
+      test "recognizes multiline escaped strings" do
+        @store.set(uri: "file:///fake.rb", source: <<~RUBY, version: 1)
+          class Test < ActiveSupport::TestCase
+            test "an example" \
+              "multiline" do
+              # test body
+            end
+          end
+        RUBY
+
+        response = RubyLsp::Executor.new(@store, @message_queue).execute({
+          method: "textDocument/codeLens",
+          params: { textDocument: { uri: "file:///fake.rb" }, position: { line: 0, character: 0 } },
+        }).response
+
+        # The first 3 responses are for the test class.
+        # The last 3 are for the test declaration.
+        assert_equal(6, response.size)
+        assert_match("Run", response[3].command.title)
+        assert_equal("bin/rails test /fake.rb:2", response[3].command.arguments[2])
+        assert_match("Run In Terminal", response[4].command.title)
+        assert_match("Debug", response[5].command.title)
+      end
+
       test "ignores unnamed tests (empty string)" do
         @store.set(uri: "file:///fake.rb", source: <<~RUBY, version: 1)
           class Test < ActiveSupport::TestCase