Skip to content

Commit

Permalink
Refactor specs and add more unhappy paths
Browse files Browse the repository at this point in the history
  • Loading branch information
lekemula committed May 19, 2024
1 parent f33e74e commit 99a4736
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 125 deletions.
2 changes: 2 additions & 0 deletions lib/solargraph/rspec/spec_walker/node_types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ def self.method_with_block_name(block_ast)
# @param block_ast [RubyVM::AbstractSyntaxTree::Node]
# @return [RubyVM::AbstractSyntaxTree::Node]
def self.context_description_node(block_ast)
return nil unless a_context_block?(block_ast)

case block_ast.children[0].type
when :CALL # RSpec.describe "something" do end
block_ast.children[0].children[2].children[0]
Expand Down
138 changes: 138 additions & 0 deletions spec/solargraph/rspec/spec_walker/node_types_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# frozen_string_literal: true

RSpec.describe Solargraph::Rspec::SpecWalker::NodeTypes do
def parse(code)
RubyVM::AbstractSyntaxTree.parse(code)
end

describe '.a_block?' do
it 'returns true for block nodes' do
node = parse('describe "something" do end')
expect(described_class.a_block?(node.children[2])).to be(true)
end

it 'returns false for non-block nodes' do
node = parse('describe "something"')
expect(described_class.a_block?(node.children[2])).to be(false)
end
end

describe '.a_context_block?' do
it 'returns true for RSpec context block nodes' do
node = parse('describe "something" do end')
expect(described_class.a_context_block?(node.children[2])).to be(true)
end

it 'returns true for RSpec root context block nodes' do
node = parse(<<~RUBY)
RSpec.describe SomeNamespace::SomeClass, type: :model do
end
RUBY

expect(described_class.a_context_block?(node.children[2])).to be(true)
end

it 'returns false for non-RSpec context block nodes' do
node = parse('different_context "something" do end')
expect(described_class.a_context_block?(node.children[2])).to be(false)
end
end

describe '.a_subject_block?' do
it 'returns true for subject block with name' do
node = parse('subject(:something) { }')
expect(described_class.a_subject_block?(node.children[2])).to be(true)
end

it 'returns true for subject block without name' do
node = parse('subject { }')

expect(described_class.a_subject_block?(node.children[2])).to be(true)
end

it 'returns false for non-subject block' do
node = parse('non_subject { }')
expect(described_class.a_subject_block?(node.children[2])).to be(false)
end
end

describe '.a_example_block?' do
it 'returns true for example block with name' do
node = parse('it("does something") { }')
expect(described_class.a_example_block?(node.children[2])).to be(true)
end

it 'returns true for example block without name' do
node = parse('it { }')

expect(described_class.a_example_block?(node.children[2])).to be(true)
end

it 'returns false for non-example block' do
node = parse('non_example { }')
expect(described_class.a_example_block?(node.children[2])).to be(false)
end
end

describe '.a_hook_block?' do
it 'returns true for example block with name' do
node = parse('before { }')
expect(described_class.a_hook_block?(node.children[2])).to be(true)
end

it 'returns false for non-hook block' do
node = parse('non_hook { }')
expect(described_class.a_hook_block?(node.children[2])).to be(false)
end
end

describe '.context_description_node' do
it 'returns correct node of context description' do
node = parse('describe "something" do end')
desc = described_class.context_description_node(node.children[2])
expect(desc.children.first).to eq('something')
end

it 'returns correct node of context root description' do
node = parse(<<~RUBY)
RSpec.describe SomeNamespace::SomeClass, type: :model do
end
RUBY

desc = described_class.context_description_node(node.children[2])
expect(desc.children.last).to eq(:SomeClass)
end

it 'returns nil for non-context block' do
node = parse('non_context "something" do end')
desc = described_class.context_description_node(node.children[2])
expect(desc).to eq(nil)
end
end

describe '.let_method_name' do
it 'returns correct method name for subject block' do
node = parse('subject(:something) { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq('something')
end

it 'returns nil for subject block without a name' do
node = parse('subject { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq(nil)
end

it 'returns correct method name for let block' do
node = parse('let(:something) { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq('something')
end

it 'returns nil for let block without a name' do
node = parse('let { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq(nil)
end
end
end
149 changes: 24 additions & 125 deletions spec/solargraph/rspec/spec_walker_spec.rb
Original file line number Diff line number Diff line change
@@ -1,120 +1,11 @@
# frozen_string_literal: true

# TODO: Add more test cases:
# - Block yields
# - NodeTypes unhappy paths
RSpec.describe Solargraph::Rspec::SpecWalker do
let(:api_map) { Solargraph::ApiMap.new }
let(:filename) { File.expand_path('spec/models/some_namespace/transaction_spec.rb') }
let(:config) { Solargraph::Rspec::Config.new }
let(:source_map) { api_map.source_maps.first }

describe Solargraph::Rspec::SpecWalker::NodeTypes do
def parse(code)
RubyVM::AbstractSyntaxTree.parse(code)
end

describe '.a_block?' do
it 'returns true for block nodes' do
node = parse('describe "something" do end')
expect(described_class.a_block?(node.children[2])).to be(true)
end
end

describe '.a_context_block?' do
it 'returns true for RSpec context block nodes' do
node = parse('describe "something" do end')
expect(described_class.a_context_block?(node.children[2])).to be(true)
end

it 'returns true for RSpec root context block nodes' do
node = parse(<<~RUBY)
RSpec.describe SomeNamespace::SomeClass, type: :model do
end
RUBY

expect(described_class.a_context_block?(node.children[2])).to be(true)
end
end

describe '.a_context_block?' do
it 'returns true for subject block with name' do
node = parse('subject(:something) { }')
expect(described_class.a_subject_block?(node.children[2])).to be(true)
end

it 'returns true for subject block without name' do
node = parse('subject { }')

expect(described_class.a_subject_block?(node.children[2])).to be(true)
end
end

describe '.a_example_block?' do
it 'returns true for example block with name' do
node = parse('it("does something") { }')
expect(described_class.a_example_block?(node.children[2])).to be(true)
end

it 'returns true for example block without name' do
node = parse('it { }')

expect(described_class.a_example_block?(node.children[2])).to be(true)
end
end

describe '.a_hook_block?' do
it 'returns true for example block with name' do
node = parse('before { }')
expect(described_class.a_hook_block?(node.children[2])).to be(true)
end
end

describe '.context_description_node' do
it 'returns correct node of context description' do
node = parse('describe "something" do end')
desc = described_class.context_description_node(node.children[2])
expect(desc.children.first).to eq('something')
end

it 'returns correct node of context root description' do
node = parse(<<~RUBY)
RSpec.describe SomeNamespace::SomeClass, type: :model do
end
RUBY

desc = described_class.context_description_node(node.children[2])
expect(desc.children.last).to eq(:SomeClass)
end
end

describe '.let_method_name' do
it 'returns correct method name for subject block' do
node = parse('subject(:something) { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq('something')
end

it 'returns nil for subject block without a name' do
node = parse('subject { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq(nil)
end

it 'returns correct method name for let block' do
node = parse('let(:something) { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq('something')
end

it 'returns nil for let block without a name' do
node = parse('let { }')
name = described_class.let_method_name(node.children[2])
expect(name).to eq(nil)
end
end
end

# @param code [String]
# @yieldparam [Solargraph::Rspec::SpecWalker]
# @return [void]
Expand All @@ -137,9 +28,10 @@ def walk_code(code)
called = 0
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_described_class do |class_name, _|
walker.on_described_class do |class_name, location_range|
called += 1
expect(class_name).to eq('SomeNamespace::SomeClass')
expect(location_range).to eq(Solargraph::Range.from_to(0, 15, 0, 39))
end
end

Expand All @@ -159,15 +51,16 @@ def walk_code(code)
end
RUBY

called = 0
let_names = []
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_let_method do |_|
called += 1
walker.on_let_method do |method_name, location_range|
let_names << method_name
expect(location_range).to be_a(Solargraph::Range)
end
end

expect(called).to eq(2)
expect(let_names).to eq(%w[test test_2])
end
end

Expand All @@ -183,15 +76,16 @@ def walk_code(code)
end
RUBY

called = 0
subject_names = []
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_subject do |_|
called += 1
walker.on_subject do |subject_name, location_range|
subject_names << subject_name
expect(location_range).to be_a(Solargraph::Range)
end
end

expect(called).to eq(2)
expect(subject_names).to eq(['test', nil])
end
end

Expand All @@ -208,15 +102,17 @@ def walk_code(code)
end
RUBY

called = 0
namespaces = []
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_each_context_block do |_|
called += 1
walker.on_each_context_block do |namespace_name, location_range|
namespaces << namespace_name
expect(location_range).to be_a(Solargraph::Range)
end
end

expect(called).to eq(2)
expect(namespaces).to eq(['RSpec::ExampleGroups::SomeNamespaceSomeClass',
'RSpec::ExampleGroups::SomeNamespaceSomeClass::WhenSomething'])
end
end

Expand All @@ -237,8 +133,9 @@ def walk_code(code)
called = 0
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_example_block do |_|
walker.on_example_block do |location_range|
called += 1
expect(location_range).to be_a(Solargraph::Range)
end
end

Expand Down Expand Up @@ -266,8 +163,9 @@ def walk_code(code)
called = 0
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_hook_block do |_|
walker.on_hook_block do |location_range|
called += 1
expect(location_range).to be_a(Solargraph::Range)
end
end

Expand Down Expand Up @@ -298,8 +196,9 @@ def walk_code(code)
called = 0
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_blocks_in_examples do |_|
walker.on_blocks_in_examples do |location_range|
called += 1
expect(location_range).to be_a(Solargraph::Range)
end
end

Expand Down

0 comments on commit 99a4736

Please sign in to comment.