rubocop-rspec icon indicating copy to clipboard operation
rubocop-rspec copied to clipboard

RSpec/DescribedClass cop throws undefined method `first' for nil:NilClass from `collapse_namespace' method

Open emailrhoads opened this issue 4 years ago • 4 comments

When running rubocop the RSpec/DescribedClass cop is throwing an error as it tries to collapse the namespace.


Expected behavior

Expect Rubocop to parse through files and not throw errors, only identify offenses.

Actual behavior

Error is thrown. Here is the stack trace.

Scanning /home/myapp/spec/controllers/myapp/diagnostic/something.rb
An error occurred while RSpec/DescribedClass cop was inspecting /home/myapp/spec/controllers/myapp/diagnostic/something.rb:4:2.
undefined method `first' for nil:NilClass
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:178:in `collapse_namespace'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:163:in `full_const_name'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:159:in `offensive_described_class?'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:143:in `offensive?'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:109:in `find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:114:in `block in find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:190:in `block in each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:113:in `find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:114:in `block in find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:190:in `block in each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:113:in `find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:114:in `block in find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:190:in `block in each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:113:in `find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:114:in `block in find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:190:in `block in each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:113:in `find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:114:in `block in find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:190:in `block in each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/node.rb:187:in `each_child_node'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:113:in `find_usage'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-rspec-1.42.0/lib/rubocop/cop/rspec/described_class.rb:88:in `on_block'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:91:in `block (2 levels) in trigger_responding_cops'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:113:in `with_cop_error_handling'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:90:in `block in trigger_responding_cops'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:89:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:89:in `trigger_responding_cops'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:61:in `block (2 levels) in <class:Commissioner>'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:159:in `on_while'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:62:in `block (2 levels) in <class:Commissioner>'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `block in on_begin'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `on_begin'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:62:in `block (2 levels) in <class:Commissioner>'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:14:in `walk'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:74:in `investigate'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/team.rb:151:in `investigate_partial'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cop/team.rb:83:in `investigate'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:295:in `inspect_file'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:245:in `block in do_inspection_loop'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:277:in `block in iterate_until_no_changes'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:270:in `loop'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:270:in `iterate_until_no_changes'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:241:in `do_inspection_loop'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:121:in `block in file_offenses'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:146:in `file_offense_cache'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:120:in `file_offenses'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:111:in `process_file'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:90:in `block in each_inspected_file'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:89:in `each'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:89:in `reduce'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:89:in `each_inspected_file'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:78:in `inspect_files'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:39:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli/command/execute_runner.rb:21:in `execute_runner'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli/command/execute_runner.rb:13:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli/command.rb:10:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli/environment.rb:17:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli.rb:65:in `run_command'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli.rb:72:in `execute_runners'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/lib/rubocop/cli.rb:41:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/exe/rubocop:13:in `block in <top (required)>'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/benchmark-0.1.0/lib/benchmark.rb:308:in `realtime'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/rubocop-0.88.0/exe/rubocop:12:in `<top (required)>'
/home/john/.rbenv/versions/2.5.7/bin/rubocop:23:in `load'
/home/john/.rbenv/versions/2.5.7/bin/rubocop:23:in `<top (required)>'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/cli/exec.rb:63:in `load'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/cli/exec.rb:63:in `kernel_load'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/cli/exec.rb:28:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/cli.rb:476:in `exec'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/cli.rb:30:in `dispatch'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/cli.rb:24:in `start'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
/home/john/.rbenv/versions/2.5.7/lib/ruby/site_ruby/2.5.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
/home/john/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
/home/john/.rbenv/versions/2.5.7/bin/bundle:23:in `load'
/home/john/.rbenv/versions/2.5.7/bin/bundle:23:in `<main>'
.

1 file inspected, no offenses detected

1 error occurred:
An error occurred while RSpec/DescribedClass cop was inspecting /home/myapp/spec/controllers/myapp/diagnostic/something.rb:4:2.
Errors are usually caused by RuboCop bugs.
Please, report your problems to RuboCop's issue tracker.
https://github.com/rubocop-hq/rubocop/issues

Steps to reproduce the problem

In the spec, I had a subject_class that was being used instead of a described class.

 describe 'Something' do
      let(:subject_class) { Myapp::Diagnostic::Something }
      let(:useful_const) { subject_class::WHATEVER }
      expect(subject_class.call).to eq(useful_const)
      ....

I cannot use described_class because I am in a controller, but my subject class does not have a request method.

NoMethodError: undefined method `request=' for #Myapp::Diagnostic::Something:0x0000559a233223b0

RuboCop version

$ [bundle exec] rubocop -V
0.88.0 (using Parser 2.7.1.4, rubocop-ast 0.3.0, running on ruby 2.5.7 x86_64-linux)

Note errors get significantly worse and less manageable if I upgrade rubocop

emailrhoads avatar Nov 12 '20 11:11 emailrhoads

I can't reproduce with rubocop-rspec-1.42.0, rubocop-0.88.0 with the following:

# frozen_string_literal: true

RSpec.describe 'Something' do
  let(:subject_class) { Myapp::Diagnostic::Something }
  let(:useful_const) { subject_class::WHATEVER }

  it do
    expect(subject_class.call).to eq(useful_const)
  end
end
1 file inspected, no offenses detected

Can you please provide a minimal spec that triggers this error?

pirj avatar Nov 12 '20 11:11 pirj

@emailrhoads Ping

pirj avatar Nov 13 '20 19:11 pirj

Will do.

emailrhoads avatar Nov 13 '20 20:11 emailrhoads

@pirj I think I stumbled upon the same issue and I have an example to reproduce it.

# frozen_string_literal: true

module Foo
  RSpec.describe Bar do
    subject(:baz) { described_class }

    it 'has a const' do
      expect(baz::SMTH).to be_present
    end
  end
end

rubocop 1.10.0 (using Parser 3.0.0.0, rubocop-ast 1.4.1, running on ruby 2.7.2 x86_64-linux-musl) rubocop-rspec 2.2.0

Note that in my case RSpec.describe is put inside a module. Hopefully, this helps. If not, I could also debug more thoroughly.

RKushnir avatar Feb 18 '21 15:02 RKushnir

I have checked and it does not reproduce now.

❯ ruby --version 
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin21]
❯ bundle exec rubocop -V                                          
1.56.0 (using Parser 3.2.2.3, rubocop-ast 1.29.0, running on ruby 3.2.2) [x86_64-darwin21]
  - rubocop-performance 1.19.0
  - rubocop-rake 0.6.0
  - rubocop-rspec 2.23.2

ydah avatar Aug 13 '23 22:08 ydah

Ah, https://github.com/rubocop/rubocop-rspec/pull/1156 is fixed this issue. If there are other issues, this Issue can be reopened or a new Issue can be created.

ydah avatar Aug 14 '23 06:08 ydah