Skip to content

Commit

Permalink
Support document symbols for shared examples (#56)
Browse files Browse the repository at this point in the history
* 👍 support shared_examples and shared_context

I add document symbol support for shared_examples and shared_context.

https://rspec.info/features/3-12/rspec-core/example-groups/shared-examples/
https://rspec.info/features/3-12/rspec-core/example-groups/shared-context/

* 👍 support shared_examples_for also

shared_examples_for is alias for shared_examples.
So I support shared_examples_for.

https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/shared_example_group.rb#L101

* 🐛 fix forget leave context issue

I forget to add on_call_node_leave for shared_... .

* ✅ Add on_call_node_leave test for shared tests

I add tests to implement on_call_node_leave for shared tests.
  • Loading branch information
byplayer authored Jan 25, 2025
1 parent 2ae636e commit f2e4170
Show file tree
Hide file tree
Showing 2 changed files with 352 additions and 2 deletions.
4 changes: 2 additions & 2 deletions lib/ruby_lsp/ruby_lsp_rspec/document_symbol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def on_call_node_enter(node)
selection_range: range_from_node(node),
range: range_from_node(node),
)
when "context", "describe"
when "context", "describe", "shared_examples", "shared_context", "shared_examples_for"
return if node.receiver && node.receiver&.slice != "RSpec"

name = generate_name(node)
Expand All @@ -57,7 +57,7 @@ def on_call_node_enter(node)
sig { params(node: Prism::CallNode).void }
def on_call_node_leave(node)
case node.message
when "context", "describe"
when "context", "describe", "shared_examples", "shared_context", "shared_examples_for"
return if node.receiver && node.receiver&.slice != "RSpec"

@response_builder.pop
Expand Down
350 changes: 350 additions & 0 deletions spec/document_symbol_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,355 @@ def test_baz; end
expect(foo.children[4].children[0].name).to eq("何かのテスト")
end
end

it "simple shared_examples" do
source = <<~RUBY
RSpec.shared_examples 'simple shared examples' do
it 'does something' do
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
shared = response[0]
expect(shared.name).to eq("simple shared examples")
expect(shared.kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(shared.children.count).to eq(1)

example = shared.children[0]
expect(example.name).to eq("does something")
expect(example.kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::METHOD)
end
end

it "symbol shared_examples" do
source = <<~RUBY
RSpec.shared_examples :symbol_shared_examples do
it 'does something in symbol' do
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
shared = response[0]
expect(shared.name).to eq(":symbol_shared_examples")
expect(shared.kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(shared.children.count).to eq(1)

child = shared.children[0]
expect(child.name).to eq("does something in symbol")
expect(child.kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::METHOD)
end
end

it "shared_examples with parameter" do
source = <<~RUBY
RSpec.shared_examples "shared example with parameter" do |parameter|
let(:something) { parameter }
it "uses the given parameter" do
expect(something).to eq(parameter)
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
shared = response[0]
expect(shared.name).to eq("shared example with parameter")
expect(shared.kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(shared.children.count).to eq(1)

child1 = shared.children[0]
expect(child1.name).to eq("uses the given parameter")
expect(child1.kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::METHOD)
end
end

it "simple shared_context" do
source = <<~RUBY
RSpec.shared_context "simple shared_context" do
before { @some_var = :some_value }
def shared_method
"it works"
end
let(:shared_let) { {'arbitrary' => 'object'} }
subject do
'this is the subject'
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
expect(response[0].name).to eq("simple shared_context")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(response[0].children.count).to eq(2)
end
end

it "symbol shared_context" do
source = <<~RUBY
RSpec.shared_context :symbol_shared_context do
before { @some_var = :some_value }
def shared_method
"it works"
end
let(:shared_let) { {'arbitrary' => 'object'} }
subject do
'this is the subject'
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
expect(response[0].name).to eq(":symbol_shared_context")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(response[0].children.count).to eq(2)
end
end

it "simple shared_examples_for" do
source = <<~RUBY
RSpec.shared_examples_for "simple shared_examples_for" do
before { @some_var = :some_value }
def shared_method
"it works"
end
let(:shared_let) { {'arbitrary' => 'object'} }
subject do
'this is the subject'
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
expect(response[0].name).to eq("simple shared_examples_for")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(response[0].children.count).to eq(2)
end
end

it "symbol shared_examples_for" do
source = <<~RUBY
RSpec.shared_examples_for :symbol_shared_examples_for do
before { @some_var = :some_value }
def shared_method
"it works"
end
let(:shared_let) { {'arbitrary' => 'object'} }
subject do
'this is the subject'
end
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(1)
expect(response[0].name).to eq(":symbol_shared_examples_for")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
expect(response[0].children.count).to eq(2)
end
end

it "on_call_node_leave for shared examples" do
source = <<~RUBY
RSpec.shared_examples "shared examples" do
end
describe "something" do
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(2)
expect(response[0].name).to eq("shared examples")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)

expect(response[1].name).to eq("something")
expect(response[1].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
end
end

it "on_call_node_leave for shared_context" do
source = <<~RUBY
RSpec.shared_context "shared context" do
end
describe "something" do
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(2)
expect(response[0].name).to eq("shared context")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)

expect(response[1].name).to eq("something")
expect(response[1].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
end
end

it "on_call_node_leave for shared_examples_for" do
source = <<~RUBY
RSpec.shared_examples_for "shared examples for" do
end
describe "something" do
end
RUBY

with_server(source, uri) do |server, uri|
server.process_message(
{
id: 2,
method: "textDocument/documentSymbol",
params: {
textDocument: { uri: uri },
},
},
)

result = server.pop_response
expect(result).to be_a(RubyLsp::Result)
response = result.response

expect(response.count).to eq(2)
expect(response[0].name).to eq("shared examples for")
expect(response[0].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)

expect(response[1].name).to eq("something")
expect(response[1].kind).to eq(LanguageServer::Protocol::Constant::SymbolKind::MODULE)
end
end
end
end

0 comments on commit f2e4170

Please sign in to comment.