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

Add a --audit flag for finding missing/unused steps #194

Merged
merged 9 commits into from
Jan 16, 2017
59 changes: 59 additions & 0 deletions features/step_auditing.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Feature: Step auditing
In order to be able to update my features
As a developer
I want spinach to automatically audit which steps are missing and obsolete

Scenario: Step file out of date
Given I have defined a "Cheezburger can I has" feature
And I have an associated step file with missing steps and obsolete steps
When I run spinach with "--audit"
Then I should see a list of unused steps
And I should see the code to paste for missing steps

Scenario: With common steps
Given I have defined a "Cheezburger can I has" feature
And I have an associated step file with some steps in a common module
When I run spinach with "--audit"
Then I should not see any steps marked as missing

Scenario: Steps not marked unused if they're in common modules
Given I have defined a "Cheezburger can I has" feature
And I have defined an "Awesome new feature" feature
And I have associated step files with common steps that are all used somewhere
When I run spinach with "--audit"
Then I should not see any steps marked as unused

Scenario: Common steps are reported as missing if not used by any feature
Given I have defined a "Cheezburger can I has" feature
And I have defined an "Awesome new feature" feature
And I have step files for both with common steps, but one common step is not used by either
When I run spinach with "--audit"
Then I should be told the extra step is unused
But I should not be told the other common steps are unused

Scenario: Tells the user to generate if step file missing
Given I have defined a "Cheezburger can I has" feature
And I have not created an associated step file
When I run spinach with "--audit"
Then I should be told to run "--generate"

Scenario: Steps still marked unused if they appear in the wrong file
Given I have defined a "Cheezburger can I has" feature
And I have defined an "Awesome new feature" feature
And I have created a step file for each with a step from one feature pasted into the other's file
When I run spinach with "--audit"
Then I should be told that step is unused

Scenario: Reports a clean audit if no steps are missing
Given I have defined a "Cheezburger can I has" feature
And I have defined an "Awesome new feature" feature
And I have complete step files for both
When I run spinach with "--audit"
Then I should be told this was a clean audit

Scenario: Should not report a step as missing more than once
Given I have defined an "Exciting feature" feature with reused steps
And I have created a step file without those reused steps
When I run spinach with "--audit"
Then I should see the missing steps reported only once

324 changes: 324 additions & 0 deletions features/steps/step_auditing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
class Spinach::Features::StepAuditing < Spinach::FeatureSteps

include Integration::SpinachRunner
step 'I have defined a "Cheezburger can I has" feature' do
write_file('features/cheezburger_can_i_has.feature', """
Feature: Cheezburger can I has
Scenario: Some Lulz
Given I haz a sad
When I get some lulz
Then I haz a happy
Scenario: Cannot haz
Given I wantz cheezburger
When I ask can haz
Then I cannot haz
""")
end

step 'I have an associated step file with missing steps and obsolete steps' do
write_file('features/steps/cheezburger_can_i_has.rb', """
class Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps
step 'I haz a sad' do
pending 'step not implemented'
end
step 'I get some roxxorz' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
step 'I ask can haz' do
pending 'step not implemented'
end
end
""")
end

step 'I run spinach with "--audit"' do
run_feature 'features', append: '--audit'
end

step 'I should see a list of unused steps' do
@stdout.must_match(/Unused step: .*cheezburger_can_i_has.rb:6 'I get some roxxorz'/)
end

step 'I should see the code to paste for missing steps' do
@stdout.must_match("Missing steps")
@stdout.must_match("step 'I get some lulz' do")
@stdout.must_match("step 'I cannot haz' do")
end

step 'I have an associated step file with some steps in a common module' do
write_file('features/steps/cheezburger_can_i_has.rb', """
class Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps
include HappySad
step 'I get some roxxorz' do
pending 'step not implemented'
end
step 'I ask can haz' do
pending 'step not implemented'
end
end
""")
write_file('features/steps/happy_sad.rb', """
module HappySad
include Spinach::DSL
step 'I haz a sad' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
end
""")
end

step 'I should not see any steps marked as missing' do
@stdout.wont_match("Missing steps")
end

step 'I should not see any steps marked as unused' do
@stdout.wont_match("Unused step")
end

step 'I have defined an "Awesome new feature" feature' do
write_file('features/awesome_new_feature.feature', """
Feature: Awesome new feature
Scenario: Awesomeness
Given I am awesome
When I do anything
Then people will cheer
""")
end

step 'I have associated step files with common steps that are all used somewhere' do
write_file('features/steps/cheezburger_can_i_has.rb', """
class Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps
include Awesome
step 'I haz a sad' do
pending 'step not implemented'
end
step 'I get some lulz' do
pending 'step not implemented'
end
step 'I wantz cheezburger' do
pending 'step not implemented'
end
step 'I ask can haz' do
pending 'step not implemented'
end
step 'I cannot haz' do
pending 'step not implemented'
end
end
""")
write_file('features/steps/awesome_new_feature.rb', """
class Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps
include Awesome
step 'I do anything' do
pending 'step not implemented'
end
end
""")
write_file('features/steps/awesome.rb', """
module Awesome
include Spinach::DSL
step 'I am awesome' do
pending 'step not implemented'
end
step 'people will cheer' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
end
""")
end

step 'I have not created an associated step file' do
# Do nothing
end

step 'I should be told to run "--generate"' do
@stdout.must_match("Step file missing: please run --generate first!")
end

step 'I have created a step file for each with a step from one feature pasted into the other\'s file' do
write_file('features/steps/cheezburger_can_i_has.rb', """
class Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps
step 'I haz a sad' do
pending 'step not implemented'
end
step 'I get some lulz' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
step 'I wantz cheezburger' do
pending 'step not implemented'
end
step 'I ask can haz' do
pending 'step not implemented'
end
step 'I cannot haz' do
pending 'step not implemented'
end
end
""")
write_file('features/steps/awesome_new_feature.rb', """
class Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps
step 'I am awesome' do
pending 'step not implemented'
end
step 'I do anything' do
pending 'step not implemented'
end
step 'people will cheer' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
end
""")
end

step 'I should be told that step is unused' do
@stdout.must_match(/Unused step: .*awesome_new_feature.rb:12 'I haz a happy'/)
end

step 'I have complete step files for both' do
write_file('features/steps/cheezburger_can_i_has.rb', """
class Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps
step 'I haz a sad' do
pending 'step not implemented'
end
step 'I get some lulz' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
step 'I wantz cheezburger' do
pending 'step not implemented'
end
step 'I ask can haz' do
pending 'step not implemented'
end
step 'I cannot haz' do
pending 'step not implemented'
end
end
""")
write_file('features/steps/awesome_new_feature.rb', """
class Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps
step 'I am awesome' do
pending 'step not implemented'
end
step 'I do anything' do
pending 'step not implemented'
end
step 'people will cheer' do
pending 'step not implemented'
end
end
""")
end

step 'I should be told this was a clean audit' do
@stdout.must_match('Audit clean - no missing steps.')
end

step 'I have defined an "Exciting feature" feature with reused steps' do
write_file('features/exciting_feature.feature', """
Feature: Exciting feature
Scenario: One
Given I exist
When I do nothing
Then I should still exist
Scenario: Two
Given I exist
When I jump up and down
Then I should still exist
""")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

end

step 'I have created a step file without those reused steps' do
write_file('features/steps/exciting_feature.rb', """

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine "" and "\nclass Spinach::Features::ExcitingFeature < Spinach::FeatureSteps\n step 'I do nothing' do\n pending 'step not implemented'\n end\nend\n" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.
Prefer single-quoted strings when you don't need string interpolation or special symbols.
Combine "\nclass Spinach::Features::ExcitingFeature < Spinach::FeatureSteps\n step 'I do nothing' do\n pending 'step not implemented'\n end\nend\n" and "" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.

class Spinach::Features::ExcitingFeature < Spinach::FeatureSteps
step 'I do nothing' do
pending 'step not implemented'
end
end
""")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

end

step 'I should see the missing steps reported only once' do
@stdout.scan('I exist').count.must_equal 1
@stdout.scan('I should still exist').count.must_equal 1
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

step 'I have step files for both with common steps, but one common step is not used by either' do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block has too many lines. [45/25]
Line is too long. [99/80]

write_file('features/steps/cheezburger_can_i_has.rb', """

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine "" and "\nclass Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps\n include Awesome\n step 'I haz a sad' do\n pending 'step not implemented'\n end\n step 'I get some lulz' do\n pending 'step not implemented'\n end\n step 'I wantz cheezburger' do\n pending 'step not implemented'\n end\n step 'I ask can haz' do\n pending 'step not implemented'\n end\n step 'I cannot haz' do\n pending 'step not implemented'\n end\nend\n" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.
Prefer single-quoted strings when you don't need string interpolation or special symbols.
Combine "\nclass Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps\n include Awesome\n step 'I haz a sad' do\n pending 'step not implemented'\n end\n step 'I get some lulz' do\n pending 'step not implemented'\n end\n step 'I wantz cheezburger' do\n pending 'step not implemented'\n end\n step 'I ask can haz' do\n pending 'step not implemented'\n end\n step 'I cannot haz' do\n pending 'step not implemented'\n end\nend\n" and "" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.

class Spinach::Features::CheezburgerCanIHas < Spinach::FeatureSteps
include Awesome
step 'I haz a sad' do
pending 'step not implemented'
end
step 'I get some lulz' do
pending 'step not implemented'
end
step 'I wantz cheezburger' do
pending 'step not implemented'
end
step 'I ask can haz' do
pending 'step not implemented'
end
step 'I cannot haz' do
pending 'step not implemented'
end
end
""")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

write_file('features/steps/awesome_new_feature.rb', """

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine "" and "\nclass Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps\n include Awesome\n step 'I am awesome' do\n pending 'step not implemented'\n end\n step 'people will cheer' do\n pending 'step not implemented';\n end\nend\n" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.
Prefer single-quoted strings when you don't need string interpolation or special symbols.
Combine "\nclass Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps\n include Awesome\n step 'I am awesome' do\n pending 'step not implemented'\n end\n step 'people will cheer' do\n pending 'step not implemented';\n end\nend\n" and "" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine "" and "\nclass Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps\n include Awesome\n step 'I am awesome' do\n pending 'step not implemented'\n end\n step 'people will cheer' do\n pending 'step not implemented';\n end\nend\n" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.
Prefer single-quoted strings when you don't need string interpolation or special symbols.
Combine "\nclass Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps\n include Awesome\n step 'I am awesome' do\n pending 'step not implemented'\n end\n step 'people will cheer' do\n pending 'step not implemented';\n end\nend\n" and "" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.

class Spinach::Features::AwesomeNewFeature < Spinach::FeatureSteps
include Awesome
step 'I am awesome' do
pending 'step not implemented'
end
step 'people will cheer' do
pending 'step not implemented';
end
end
""")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

write_file('features/steps/awesome.rb', """

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine "" and "\nmodule Awesome\n include Spinach::DSL\n step 'I do anything' do\n pending 'step not implemented'\n end\n step 'I haz a happy' do\n pending 'step not implemented'\n end\n step 'I enter the void' do\n pending 'step not implemented'\n end\nend\n" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.
Prefer single-quoted strings when you don't need string interpolation or special symbols.
Combine "\nmodule Awesome\n include Spinach::DSL\n step 'I do anything' do\n pending 'step not implemented'\n end\n step 'I haz a happy' do\n pending 'step not implemented'\n end\n step 'I enter the void' do\n pending 'step not implemented'\n end\nend\n" and "" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma.

module Awesome
include Spinach::DSL
step 'I do anything' do
pending 'step not implemented'
end
step 'I haz a happy' do
pending 'step not implemented'
end
step 'I enter the void' do
pending 'step not implemented'
end
end
""")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

end

step 'I should be told the extra step is unused' do
@stdout.must_match(/Unused step: .*awesome.rb:10 'I enter the void'/)
end

step 'I should not be told the other common steps are unused' do
@stdout.wont_match('I do anything')
@stdout.wont_match('I haz a happy')
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

step 'bad' do
pending 'hello'
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

end
2 changes: 1 addition & 1 deletion features/support/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
end


Spinach.hooks.after_run do |scenario|
Spinach.hooks.after_scenario do |scenario|

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused block argument - scenario. You can omit the argument if you don't care about it.

FileUtils.rm_rf(Filesystem.dirs)
end
Loading