Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolving spec DSL references #21

Open
johnmaxwell opened this issue Jan 31, 2024 · 4 comments
Open

Resolving spec DSL references #21

johnmaxwell opened this issue Jan 31, 2024 · 4 comments
Labels
enhancement New feature or request

Comments

@johnmaxwell
Copy link

johnmaxwell commented Jan 31, 2024

One of the most challenging things about working with Rspec tests that have been written in a subject-let-fixture style is tracking down the definitions of subjects and lets -- especially when the test file gets pretty long. This is a process that computers are better at than human brains. I feel like it would be hugely beneficial to offer something akin to go-to-definition for subjects and lets within a spec-formatted ruby file.

As someone who works on this project and ruby-lsp, how achievable would something like this be via a ruby-lsp addon? It seems the add-on would need its own index, similar to RubyIndexer, capable of interpreting and building an index from a spec DSL.

@st0012
Copy link
Owner

st0012 commented Feb 10, 2024

tracking down the definitions of subjects and lets

Can you give me a few examples? Like do you mean when you cmd+click a subject call, it brings you to the associated subject { ... } block?

If that's the case, then it's pretty difficult to do it 100% accurate atm because subject could be:

  1. a local variable
  2. a method
  3. a RSpec subject

And for let it's even harder as it could be inherited from outer scopes.

Maybe we can use the document highlight feature to highlight potential subject(:foo) or let(:foo) when pointing at foo?

@johnmaxwell
Copy link
Author

Thanks for taking the time to review and respond @st0012 !

Here's a simplified example of what I'm talking about. It's not great testing code, but it seems fairly typical for an rspec suite.

describe "#can_make_reservation?" do
  let(:user) { User.new(active: true) }
  subject { Reserver.new(user) }

  context "when the user is active" do
    it "is true" do
      expect(subject.can_make_reservation?).to eq true
    end
  end

  context "when the user is inactive" do
    let(:user) { User.new(active: false) }

    it "is false" do
      expect(subject.can_make_reservation?).to eq false
    end
  end
end

Could we help the user track down the subject/let fixtures for a given example?

The first example's ("#can_make_reservation? when user is active is true") text fixtures are the subject defined on line 3 and the let(:user) defined on line 2.

The second example's ("#can_make_reservation? when user is inactive is false") test fixtures are the subject defined on line 3 and the let(:user) defined on line 12, because user has been overridden within the nested context.

This is mental work that has to be done every time a human tries to maintain an rspec suite. It's work that becomes significantly more burdensome as the length and nesting-depth of an rspec test file grows.

Somehow what example you're interested in has to be established, otherwise the resolution wouldn't work correctly.

A naive go-to-method would work fine for the first example ("#can_make_reservation? when user is active is true"). The user could command-click subject on line 7 and be brought to the subject definition on line 3. Then, they could command-click user within the subject's block on line 3 and be brought to the let(:user) definition on line 2.

But for the second example ("#can_make_reservation? when user is inactive is false"), we'd need a different strategy that would respect the overridden let(:user) from line 12. So maybe a simple go-to-method doesn't work -- or at least it would need to be biased to the example the user is interested in.

Could there be an editor command to "print example fixtures" could be run for a given example? Using it for first example, would print out:

03: subject { Reserver.new(user) }
02: let(:user) { User.new(active: true) }

Using it for the second example would print out:

03: subject { Reserver.new(user) }
12: let(:user) { User.new(active: false) }

Does this help? Thank you again for taking the time to review and respond.

@st0012
Copy link
Owner

st0012 commented Jun 15, 2024

I tried to prototype something today, but it's not possible without some addon API changes from ruby-lsp itself, which I proposed in Shopify/ruby-lsp#2191.

@st0012 st0012 added the enhancement New feature or request label Jun 15, 2024
@johnmaxwell
Copy link
Author

@st0012 Nice! Thank you for looking into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants