pax_global_header00006660000000000000000000000064151275615740014527gustar00rootroot0000000000000052 comment=f7aecf0580cda23bd5b25c3cfddddefabb6228bc rubocop-rubocop-rspec-a5aeb29/000077500000000000000000000000001512756157400164535ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/.codespellignore000066400000000000000000000000121512756157400216230ustar00rootroot00000000000000xdescribe rubocop-rubocop-rspec-a5aeb29/.git-blame-ignore-revs000066400000000000000000000004421512756157400225530ustar00rootroot00000000000000# .git-blame-ignore-revs # Add mdformat to the workflow in GitHub Actions 4874a5a4a2a58e76d343aaa02279cd93b16f5a30 # Move node patterns into private scope 089491fb1fa173145f8e6eb1b511d4a7a1bf28ff # Don't always define node patterns in private scope ce09cb2b25b9f3778bf032d0caaa862da6635b54 rubocop-rubocop-rspec-a5aeb29/.gitattributes000066400000000000000000000000311512756157400213400ustar00rootroot00000000000000CHANGELOG.md merge=union rubocop-rubocop-rspec-a5aeb29/.github/000077500000000000000000000000001512756157400200135ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/.github/CODEOWNERS000066400000000000000000000000321512756157400214010ustar00rootroot00000000000000* @rubocop/rubocop-rspec rubocop-rubocop-rspec-a5aeb29/.github/CONTRIBUTING.md000066400000000000000000000077521512756157400222570ustar00rootroot00000000000000# Contributing If you encounter problems or have ideas for improvements or new features, please report them to the [issue tracker](https://github.com/rubocop/rubocop-rspec/issues) or submit a pull request. Please, try to follow these guidelines when you do so. ## Issue reporting - Check that the issue has not already been reported. - Check that the issue has not already been fixed in the latest code (a.k.a. `master`). - Check if the issue is a non-goal of RuboCop RSpec. - Be clear, concise, and precise in your description of the problem. - Open an issue with a descriptive title and a summary in grammatically correct, complete sentences. - Report the versions of `rubocop-rspec`, as well as the output of `rubocop -V`. - Include any relevant code to the issue summary. ## Pull requests 1. Fork the project. 2. Create a feature branch. 3. Make sure to add tests. 4. Make sure the test suite passes (run `rake`). 5. Add a [changelog](https://github.com/rubocop/rubocop-rspec/blob/master/CHANGELOG.md) entry. 6. Commit your changes. 7. Push to the branch. 8. Create new Pull Request. ### Spell Checking We are running [codespell](https://github.com/codespell-project/codespell) with [GitHub Actions](https://github.com/rubocop/rubocop-rspec/blob/master/.github/workflows/codespell.yml) to check spelling and [codespell](https://pypi.org/project/codespell/). `codespell` is written in [Python](https://www.python.org/) and you can run it with: ```console $ codespell --ignore-words=.codespellignore ``` ### Linting YAML files We are running [yamllint](https://github.com/adrienverge/yamllint) for linting YAML files. This is also run by [GitHub Actions](https://github.com/rubocop/rubocop-rspec/blob/master/.github/workflows/linting.yml). `yamllint` is written in [Python](https://www.python.org/) and you can run it with: ```console $ yamllint . ``` ### Formatting Markdown files We are running [mdformat](https://github.com/executablebooks/mdformat) for formatting Markdown files. This is also run by [GitHub Actions](https://github.com/rubocop/rubocop-rspec/blob/master/.github/workflows/linting.yml). `mdformat` is written in [Python](https://www.python.org/) and you can run it with: ```console $ mdformat . --number ``` ### Test Coverage - Line and Branch We are using [Simplecov](https://github.com/colszowka/simplecov) to track test coverage. It is included and reported when you run `bundle exec rake` or `bundle exec rspec`. To view the coverage report, open the `coverage/index.html` file in your browser. E.g. on macOS: ```console $ open coverage/index.html ``` If you have unreachable lines, you can add `# :nocov` around those lines. The code itself or a comment should explain why the line is unreachable. Example: ```ruby # :nocov: raise ArgumentError("Unsupported style :#{style}") # :nocov: ``` This can happen for a few reasons, including: 1. When you handle config with a case statement and there is no else block. 2. When matching with a node pattern even when you handle all cases: all other node types will be excluded before reaching your handler, because the node pattern will not match them. You will need full line and branch coverage to merge. This helps detect edge cases and prevent errors. ## Creating new cops - Document examples of good and bad code in your cop. - Add an entry to `config/default.yml`. It's an ordered list, so be sure to insert at the appropriate place. - Run `bundle exec rake`. This will verify that the build passes as well as generate documentation and ensure that `config/default.yml` is up to date (don't forget to commit the documentation). - Add tests for as many use cases as you can think of. Always add tests for both bad code that should register an offense and good code that should not. - Common pitfalls: - If your cop inspects code outside of an example, check for false positives when similarly named variables are used inside of the example. - If your cop inspects code inside of an example, check that it works when the example is empty (empty `describe`, `it`, etc.). rubocop-rubocop-rspec-a5aeb29/.github/ISSUE_TEMPLATE/000077500000000000000000000000001512756157400221765ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000031451512756157400246730ustar00rootroot00000000000000--- name: Bug Report about: Report an issue with RuboCop RSpec you've discovered. --- *Be clear, concise and precise in your description of the problem. Open an issue with a descriptive title and a summary in grammatically correct, complete sentences.* *Use the template below when reporting bugs. Please, make sure that you're running the latest stable RuboCop RSpec and that the problem you're reporting hasn't been reported (and potentially fixed) already.* *Before filing the ticket you should replace all text above the horizontal rule with your own words.* *In the case of false positive or false negative, please add the corresponding cop name.* ______________________________________________________________________ ## Steps to reproduce the problem This is extremely important! Providing us with a reliable way to reproduce a problem will expedite its solution. ## Expected behavior Describe here how you expected RuboCop RSpec to behave in this particular situation. ## Actual behavior Describe here what actually happened. Please use `rubocop --debug` when pasting rubocop output as it contains additional information. ## RuboCop RSpec version Include the output of `rubocop -V` or `bundle exec rubocop -V` if using Bundler. If you see extension cop versions (e.g. `rubocop-performance`, `rubocop-rake`, and others) output by `rubocop -V`, include them as well. Here's an example: ```shell $ [bundle exec] rubocop -V 1.67.0 (using Parser 3.3.5.0, rubocop-ast 1.32.3, analyzing as Ruby 2.7, running on ruby 3.4.0) [arm64-darwin23] - rubocop-performance 1.22.1 - rubocop-rake 0.6.0 - rubocop-rspec 3.1.0 ``` rubocop-rubocop-rspec-a5aeb29/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011271512756157400257240ustar00rootroot00000000000000--- name: Feature Request about: Suggest new RuboCop RSpec features or improvements to existing features. --- ## Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] ## Describe the solution you'd like A clear and concise description of what you want to happen. ## Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered. ## Additional context Add any other context or screenshots about the feature request here. rubocop-rubocop-rspec-a5aeb29/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000022601512756157400236140ustar00rootroot00000000000000**Replace this text with a summary of the changes in your PR. The more detailed you are, the better.** ______________________________________________________________________ Before submitting the PR make sure the following are checked: - [ ] Feature branch is up-to-date with `master` (if not - rebase it). - [ ] Squashed related commits together. - [ ] Added tests. - [ ] Updated documentation. - [ ] Added an entry to the `CHANGELOG.md` if the new code introduces user-observable changes. - [ ] The build (`bundle exec rake`) passes (be sure to run this locally, since it may produce updated documentation that you will need to commit). If you have created a new cop: - [ ] Added the new cop to `config/default.yml`. - [ ] The cop is configured as `Enabled: pending` in `config/default.yml`. - [ ] The cop is configured as `Enabled: true` in `.rubocop.yml`. - [ ] The cop documents examples of good and bad code. - [ ] The tests assert both that bad code is reported and that good code is not reported. - [ ] Set `VersionAdded: "<>"` in `default/config.yml`. If you have modified an existing cop's configuration options: - [ ] Set `VersionChanged: "<>"` in `config/default.yml`. rubocop-rubocop-rspec-a5aeb29/.github/dependabot.yml000066400000000000000000000001661512756157400226460ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: 'github-actions' directory: '/' schedule: interval: 'weekly' rubocop-rubocop-rspec-a5aeb29/.github/workflows/000077500000000000000000000000001512756157400220505ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/.github/workflows/codespell.yml000066400000000000000000000007161512756157400245510ustar00rootroot00000000000000name: CodeSpell on: - pull_request concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: codespell: name: CodeSpell runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: CodeSpell uses: codespell-project/actions-codespell@master with: check_filenames: true check_hidden: true ignore_words_file: .codespellignore rubocop-rubocop-rspec-a5aeb29/.github/workflows/linting.yml000066400000000000000000000014331512756157400242400ustar00rootroot00000000000000name: Linting on: - pull_request concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: yamllint: name: Yamllint runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Yamllint uses: karancode/yamllint-github-action@master with: yamllint_strict: true yamllint_format: parsable yamllint_comment: true env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} mdformat: name: Mdformat runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Mdformat uses: ydah/mdformat-action@main with: number: true env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} rubocop-rubocop-rspec-a5aeb29/.github/workflows/main.yml000066400000000000000000000075521512756157400235300ustar00rootroot00000000000000name: CI on: pull_request: push: branches: - master concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: confirm_config_and_documentation: runs-on: ubuntu-latest name: Confirm config and documentation steps: - uses: actions/checkout@v6 - uses: ruby/setup-ruby@v1 with: ruby-version: ruby bundler-cache: true - run: bundle exec rake confirm_config documentation_syntax_check confirm_documentation main: runs-on: ubuntu-latest strategy: matrix: ruby: - "2.7" - "3.0" - "3.1" - "3.2" - "3.3" - "3.4" - "4.0" - ruby-head - jruby-9.4 task: - internal_investigation - spec name: "Ruby ${{ matrix.ruby }}: ${{ matrix.task }}" steps: - uses: actions/checkout@v6 - uses: ruby/setup-ruby@v1 with: ruby-version: "${{ matrix.ruby }}" bundler-cache: true - run: NO_COVERAGE=true bundle exec rake ${{ matrix.task }} coverage: runs-on: ubuntu-latest name: "Test coverage" steps: - uses: actions/checkout@v6 - uses: ruby/setup-ruby@v1 with: ruby-version: ruby bundler-cache: true - run: bundle exec rake spec edge-rubocop: runs-on: ubuntu-latest strategy: matrix: task: - internal_investigation - spec name: "Edge RuboCop: ${{ matrix.task }}" steps: - uses: actions/checkout@v6 - name: Use latest RuboCop from `master` run: | echo "gem 'rubocop', github: 'rubocop/rubocop'" > Gemfile.local cat Gemfile.local - uses: ruby/setup-ruby@v1 with: ruby-version: ruby bundler-cache: true - name: Show RuboCop version run: grep '^ rubocop' Gemfile.lock | sort - run: NO_COVERAGE=true bundle exec rake ${{ matrix.task }} oldest-rubocop: runs-on: ubuntu-latest strategy: matrix: task: - spec name: "Oldest RuboCop: ${{ matrix.task }}" steps: - uses: actions/checkout@v6 - name: Use oldest RuboCop allowed by gemspec run: | sed -nr "s/ *spec.add_dependency 'rubocop'.*'>= ([0-9\.]+)'/gem 'rubocop', '= \1'/p" \ rubocop-rspec.gemspec > Gemfile.local cat Gemfile.local - uses: ruby/setup-ruby@v1 with: ruby-version: ruby bundler-cache: true - name: Show RuboCop version run: grep '^ rubocop' Gemfile.lock | sort - run: NO_COVERAGE=true bundle exec rake ${{ matrix.task }} rspec4: runs-on: ubuntu-latest name: RSpec 4 steps: - uses: actions/checkout@v6 - name: Use latest RSpec 4 from `4-0-dev` branch run: | sed -e '/rspec/d' -i Gemfile cat << EOF > Gemfile.local gem 'rspec', github: 'rspec/rspec', branch: '4-0-dev' gem 'rspec-core', github: 'rspec/rspec', branch: '4-0-dev' gem 'rspec-expectations', github: 'rspec/rspec', branch: '4-0-dev' gem 'rspec-mocks', github: 'rspec/rspec', branch: '4-0-dev' gem 'rspec-support', github: 'rspec/rspec', branch: '4-0-dev' EOF - uses: ruby/setup-ruby@v1 with: ruby-version: ruby bundler-cache: true - run: NO_COVERAGE=true bundle exec rake spec prism: runs-on: ubuntu-latest name: Prism steps: - uses: actions/checkout@v6 - name: set up Ruby uses: ruby/setup-ruby@v1 with: # Specify the minimum Ruby version 2.7 required for Prism to run. ruby-version: "2.7" bundler-cache: true - env: NO_COVERAGE: true PARSER_ENGINE: parser_prism run: bundle exec rake spec rubocop-rubocop-rspec-a5aeb29/.github/workflows/publish.yml000066400000000000000000000027271512756157400242510ustar00rootroot00000000000000name: Publish on: push: branches: master paths: lib/rubocop/rspec/version.rb jobs: publish: name: Publish to RubyGems runs-on: ubuntu-latest if: github.repository_owner == 'rubocop' permissions: actions: write contents: write id-token: write pull-requests: write steps: - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: bundler-cache: true ruby-version: ruby - uses: rubygems/release-gem@v1 - name: Create a GitHub release env: GH_TOKEN: ${{ github.token }} run: | bundle exec rake create_release_notes gh release create $(git tag --points-at @) \ --title "RuboCop RSpec $(git tag --points-at @)" \ --notes-file relnotes.md - name: Replace version in Antora config env: GH_TOKEN: ${{ github.token }} run: | sed -i 's/version:.*$/version: ~/' docs/antora.yml if ! git diff --exit-code docs/antora.yml; then branch=switch-docs-version-$(git tag --points-at @) git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" git checkout -b "$branch" git add docs/antora.yml git commit -m "Switch docs version back" git push -u origin "$branch" gh pr create --fill --head "$branch" fi rubocop-rubocop-rspec-a5aeb29/.gitignore000066400000000000000000000003521512756157400204430ustar00rootroot00000000000000# rdoc generated rdoc # yard generated doc .yardoc # bundler .bundle Gemfile.lock Gemfile.local # jeweler generated pkg /vendor .ruby-gemset .ruby-version # simplecov generated coverage # vscode generated .vscode /relnotes.md rubocop-rubocop-rspec-a5aeb29/.rspec000066400000000000000000000000551512756157400175700ustar00rootroot00000000000000--require spec_helper --format documentation rubocop-rubocop-rspec-a5aeb29/.rubocop.yml000066400000000000000000000223521512756157400207310ustar00rootroot00000000000000inherit_from: .rubocop_todo.yml plugins: - rubocop-performance - rubocop-rake - rubocop-rspec - rubocop-internal_affairs AllCops: DisplayCopNames: true TargetRubyVersion: 2.7 NewCops: disable Exclude: - 'vendor/**/*' - 'spec/fixtures/**/*' - 'tmp/**/*' - 'spec/smoke_tests/**/*.rb' InternalAffairs/OnSendWithoutOnCSend: Enabled: false Layout/HashAlignment: EnforcedHashRocketStyle: - key - table EnforcedColonStyle: - key - table Layout/LineLength: Max: 80 # default: 120 AllowedPatterns: - '^\s*# .*https?:\/\/.+\[.+\]\.?$' # Allow long asciidoc links Layout/MultilineMethodCallIndentation: EnforcedStyle: indented Layout/MultilineOperationIndentation: EnforcedStyle: indented Lint/InterpolationCheck: Exclude: - spec/**/*.rb # When the `edge-rubocop` build is red, and we decide to disable the cop, # the rest of the builds become red if the cop has not yet been released. # Instead of waiting for RuboCop releases to make `edge-rubocop` green, # we prefer keeping disable directives here and there and check if they # are still needed once in a while. Lint/RedundantCopDisableDirective: Enabled: false Lint/UselessAccessModifier: MethodCreatingMethods: - def_node_matcher - def_node_search Metrics/BlockLength: Exclude: - rubocop-rspec.gemspec - Rakefile - '**/*.rake' Metrics/MethodLength: Max: 15 Naming/FileName: Exclude: - lib/rubocop-rspec.rb Naming/InclusiveLanguage: Enabled: true CheckStrings: true FlaggedTerms: ' a offense': Suggestions: - an offense auto-correct: Suggestions: - autocorrect auto_correct: Suggestions: - autocorrect ' a violation': Suggestions: - an offense behaviour: Suggestions: - behavior offence: Suggestions: - offense 'does not registers': Suggestions: - does not register violation: Suggestions: - offense 'register no offense': Suggestions: - registers no offense RSpec: Language: Expectations: - expect_correction - expect_no_offenses - expect_offense RSpec/DescribeClass: Exclude: - spec/project/**/*.rb RSpec/ExampleLength: CountAsOne: - heredoc Max: 11 RSpec/MultipleExpectations: Max: 2 RSpec/SpecFilePathFormat: Exclude: - spec/rubocop/cop/rspec/mixin/**/*.rb # `expect_offense` does not use Kernel#format or String#% Style/FormatStringToken: Exclude: - spec/rubocop/**/*.rb Style/NumberedParameters: Enabled: true EnforcedStyle: disallow Style/RequireOrder: Enabled: true # Enable RuboCop's pending cops up to v1.72 Gemspec/AddRuntimeDependency: {Enabled: true} Gemspec/DeprecatedAttributeAssignment: {Enabled: true} Gemspec/DevelopmentDependencies: {Enabled: true} Gemspec/RequireMFA: {Enabled: true} Layout/LineContinuationLeadingSpace: {Enabled: true} Layout/LineContinuationSpacing: {Enabled: true} Layout/LineEndStringConcatenationIndentation: {Enabled: true} Layout/SpaceBeforeBrackets: {Enabled: true} Lint/AmbiguousAssignment: {Enabled: true} Lint/AmbiguousOperatorPrecedence: {Enabled: true} Lint/AmbiguousRange: {Enabled: true} Lint/ArrayLiteralInRegexp: {Enabled: true} Lint/ConstantOverwrittenInRescue: {Enabled: true} Lint/ConstantReassignment: {Enabled: true} Lint/CopDirectiveSyntax: {Enabled: true} Lint/DeprecatedConstants: {Enabled: true} Lint/DuplicateBranch: {Enabled: true} Lint/DuplicateMagicComment: {Enabled: true} Lint/DuplicateMatchPattern: {Enabled: true} Lint/DuplicateRegexpCharacterClassElement: {Enabled: true} Lint/DuplicateSetElement: {Enabled: true} Lint/EmptyBlock: {Enabled: true} Lint/EmptyClass: {Enabled: true} Lint/EmptyInPattern: {Enabled: true} Lint/HashNewWithKeywordArgumentsAsDefault: {Enabled: true} Lint/IncompatibleIoSelectWithFiberScheduler: {Enabled: true} Lint/ItWithoutArgumentsInBlock: {Enabled: true} Lint/LambdaWithoutLiteralBlock: {Enabled: true} Lint/LiteralAssignmentInCondition: {Enabled: true} Lint/MixedCaseRange: {Enabled: true} Lint/NonAtomicFileOperation: {Enabled: true} Lint/NoReturnInBeginEndBlocks: {Enabled: true} Lint/NumberedParameterAssignment: {Enabled: true} Lint/NumericOperationWithConstantResult: {Enabled: true} Lint/OrAssignmentToConstant: {Enabled: true} Lint/RedundantDirGlobSort: {Enabled: true} Lint/RedundantRegexpQuantifiers: {Enabled: true} Lint/RedundantTypeConversion: {Enabled: true} Lint/RefinementImportMethods: {Enabled: true} Lint/RequireRangeParentheses: {Enabled: true} Lint/RequireRelativeSelfPath: {Enabled: true} Lint/SharedMutableDefault: {Enabled: true} Lint/SuppressedExceptionInNumberConversion: {Enabled: true} Lint/SymbolConversion: {Enabled: true} Lint/ToEnumArguments: {Enabled: true} Lint/TripleQuotes: {Enabled: true} Lint/UnescapedBracketInRegexp: {Enabled: true} Lint/UnexpectedBlockArity: {Enabled: true} Lint/UnmodifiedReduceAccumulator: {Enabled: true} Lint/UselessConstantScoping: {Enabled: true} Lint/UselessDefined: {Enabled: true} Lint/UselessNumericOperation: {Enabled: true} Lint/UselessRescue: {Enabled: true} Lint/UselessRuby2Keywords: {Enabled: true} Metrics/CollectionLiteralLength: {Enabled: true} Naming/BlockForwarding: {Enabled: true} Security/CompoundHash: {Enabled: true} Security/IoMethods: {Enabled: true} Style/AmbiguousEndlessMethodDefinition: {Enabled: true} Style/ArgumentsForwarding: {Enabled: true} Style/ArrayIntersect: {Enabled: true} Style/BitwisePredicate: {Enabled: true} Style/CollectionCompact: {Enabled: true} Style/CombinableDefined: {Enabled: true} Style/ComparableClamp: {Enabled: true} Style/ConcatArrayLiterals: {Enabled: true} Style/DataInheritance: {Enabled: true} Style/DigChain: {Enabled: true} Style/DirEmpty: {Enabled: true} Style/DocumentDynamicEvalDefinition: {Enabled: true} Style/EmptyHeredoc: {Enabled: true} Style/EndlessMethod: {Enabled: true} Style/EnvHome: {Enabled: true} Style/ExactRegexpMatch: {Enabled: true} Style/FetchEnvVar: {Enabled: true} Style/FileEmpty: {Enabled: true} Style/FileNull: {Enabled: true} Style/FileRead: {Enabled: true} Style/FileTouch: {Enabled: true} Style/FileWrite: {Enabled: true} Style/HashConversion: {Enabled: true} Style/HashExcept: {Enabled: true} Style/HashSlice: {Enabled: true} Style/IfWithBooleanLiteralBranches: {Enabled: true} Style/InPatternThen: {Enabled: true} Style/ItAssignment: {Enabled: true} Style/KeywordArgumentsMerging: {Enabled: true} Style/MagicCommentFormat: {Enabled: true} Style/MapCompactWithConditionalBlock: {Enabled: true} Style/MapIntoArray: {Enabled: true} Style/MapToHash: {Enabled: true} Style/MapToSet: {Enabled: true} Style/MinMaxComparison: {Enabled: true} Style/MultilineInPatternThen: {Enabled: true} Style/NegatedIfElseCondition: {Enabled: true} Style/NestedFileDirname: {Enabled: true} Style/NilLambda: {Enabled: true} Style/NumberedParametersLimit: {Enabled: true} Style/ObjectThen: {Enabled: true} Style/OpenStructUse: {Enabled: true} Style/OperatorMethodCall: {Enabled: true} Style/QuotedSymbols: {Enabled: true} Style/RedundantArgument: {Enabled: true} Style/RedundantArrayConstructor: {Enabled: true} Style/RedundantConstantBase: {Enabled: true} Style/RedundantCurrentDirectoryInPath: {Enabled: true} Style/RedundantDoubleSplatHashBraces: {Enabled: true} Style/RedundantEach: {Enabled: true} Style/RedundantFilterChain: {Enabled: true} Style/RedundantFormat: {Enabled: true} Style/RedundantHeredocDelimiterQuotes: {Enabled: true} Style/RedundantInitialize: {Enabled: true} Style/RedundantInterpolationUnfreeze: {Enabled: true} Style/RedundantLineContinuation: {Enabled: true} Style/RedundantRegexpArgument: {Enabled: true} Style/RedundantRegexpConstructor: {Enabled: true} Style/RedundantSelfAssignmentBranch: {Enabled: true} Style/RedundantStringEscape: {Enabled: true} Style/ReturnNilInPredicateMethodDefinition: {Enabled: true} Style/SafeNavigationChainLength: {Enabled: true} Style/SelectByRegexp: {Enabled: true} Style/SendWithLiteralMethodName: {Enabled: true} Style/SingleLineDoEndBlock: {Enabled: true} Style/StringChars: {Enabled: true} Style/SuperArguments: {Enabled: true} Style/SuperWithArgsParentheses: {Enabled: true} Style/SwapValues: {Enabled: true} Style/YAMLFileRead: {Enabled: true} # Enable RuboCop Performance's pending cops up to v1.24 Performance/AncestorsInclude: {Enabled: true} Performance/BigDecimalWithNumericArgument: {Enabled: true} Performance/BlockGivenWithExplicitBlock: {Enabled: true} Performance/CollectionLiteralInLoop: {Enabled: true} Performance/ConcurrentMonotonicTime: {Enabled: true} Performance/ConstantRegexp: {Enabled: true} Performance/MapCompact: {Enabled: true} Performance/MapMethodChain: {Enabled: true} Performance/MethodObjectAsBlock: {Enabled: true} Performance/RedundantEqualityComparisonBlock: {Enabled: true} Performance/RedundantSortBlock: {Enabled: true} Performance/RedundantSplitRegexpArgument: {Enabled: true} Performance/RedundantStringChars: {Enabled: true} Performance/ReverseFirst: {Enabled: true} Performance/SortReverse: {Enabled: true} Performance/Squeeze: {Enabled: true} Performance/StringBytesize: {Enabled: true} Performance/StringIdentifierArgument: {Enabled: true} Performance/StringInclude: {Enabled: true} Performance/Sum: {Enabled: true} Performance/ZipWithoutBlock: {Enabled: true} # Enable our own pending cops. RSpec/IncludeExamples: {Enabled: true} RSpec/LeakyLocalVariable: {Enabled: true} RSpec/Output: {Enabled: true} rubocop-rubocop-rspec-a5aeb29/.rubocop_todo.yml000066400000000000000000000007351512756157400217570ustar00rootroot00000000000000# This configuration was generated by # `rubocop --auto-gen-config --no-offense-counts --no-auto-gen-timestamp` # using RuboCop version 1.72.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. Rake/MethodDefinitionInTask: Exclude: - 'tasks/cut_release.rake' rubocop-rubocop-rspec-a5aeb29/.simplecov000066400000000000000000000002571512756157400204610ustar00rootroot00000000000000# frozen_string_literal: true SimpleCov.start do enable_coverage :branch minimum_coverage line: 100, branch: 100 add_filter '/spec/' add_filter '/vendor/bundle/' end rubocop-rubocop-rspec-a5aeb29/.yamllint000066400000000000000000000003101512756157400202770ustar00rootroot00000000000000extends: default rules: comments: min-spaces-from-content: 1 document-start: disable line-length: allow-non-breakable-inline-mappings: true max: 100 truthy: check-keys: false rubocop-rubocop-rspec-a5aeb29/.yardopts000066400000000000000000000001131512756157400203140ustar00rootroot00000000000000--markup markdown --hide-void-return --tag safety:"Cop Safety Information" rubocop-rubocop-rspec-a5aeb29/CHANGELOG.md000066400000000000000000001665311512756157400203000ustar00rootroot00000000000000# Changelog ## Master (Unreleased) ## 3.9.0 (2026-01-07) - Fix a false positive for `RSpec/LeakyLocalVariable` when variables are used only in example metadata (e.g., skip messages). ([@ydah]) - Fix a false positive for `RSpec/ScatteredSetup` when the hook is defined inside a class method. ([@d4rky-pl]) - Fix a false positive for `RSpec/DescribedClass` inside dynamically evaluated blocks (`class_eval`, `module_eval`, `instance_eval`, `class_exec`, `module_exec`, `instance_exec`). ([@sucicfilip]) - Add new cop `RSpec/Output`. ([@kevinrobell-st]) ## 3.8.0 (2025-11-12) - Add new cop `RSpec/LeakyLocalVariable`. ([@lovro-bikic]) - Bump RuboCop requirement to +1.81. ([@ydah]) - Fix a false positive for `RSpec/LetSetup` when `let!` used in outer scope. ([@ydah]) - Fix a false positive for `RSpec/ReceiveNever` cop when `allow(...).to receive(...).never`. ([@ydah]) - Fix detection of nameless doubles with methods in `RSpec/VerifiedDoubles`. ([@ushi-as]) - Improve an offense message for `RSpec/RepeatedExample` cop. ([@ydah]) - Let `RSpec/SpecFilePathFormat` leverage ActiveSupport inflections when configured. ([@corsonknowles], [@bquorning]) ## 3.7.0 (2025-09-01) - Mark `RSpec/IncludeExamples` as `SafeAutoCorrect: false`. ([@yujideveloper]) - Fix a false positive for `RSpec/LeakyConstantDeclaration` when defining constants in explicit namespaces. ([@naveg]) - Add support for error matchers (`raise_exception` and `raise_error`) to `RSpec/Dialect`. ([@lovro-bikic]) - Don't register offenses for `RSpec/DescribedClass` within `Data.define` blocks. ([@lovro-bikic]) - Add autocorrection support for `RSpec/IteratedExpectation` for single expectations. ([@lovro-bikic]) - Exclude all cops from inspecting factorybot files, except if explicitly included. ([@Mth0158]) - Fix a false positive for `RSpec/ExcessiveDocstringSpacing` when receivers are not RSpec methods. ([@ydah]) ## 3.6.0 (2025-04-18) - Fix false positive in `RSpec/Pending`, where it would mark the default block `it` as an offense. ([@bquorning]) - Fix issue when `Style/ContextWording` is configured with a Prefix being interpreted as a boolean, like `on`. ([@sakuro]) - Add new `RSpec/IncludeExamples` cop to enforce using `it_behaves_like` over `include_examples`. ([@dvandersluis]) - Change `RSpec/ScatteredSetup` to allow `around` hooks to be scattered. ([@ydah]) - Fix an error `RSpec/ChangeByZero` cop when without expect block. ([@lee266]) - Fix a false positive for `RSpec/DescribedClass` when `SkipBlocks` is true and numblocks are used. ([@earlopain]) ## 3.5.0 (2025-02-16) - Don't let `RSpec/PredicateMatcher` replace `respond_to?` with two arguments with the RSpec `respond_to` matcher. ([@bquorning]) - Fix `RSpec/PredicateMatcher` support for `eql` and `equal` matchers. ([@bquorning]) - Pluginfy RuboCop RSpec. ([@koic]) ## 3.4.0 (2025-01-20) - Fix `RSpec/SortMetadata` cop to limit sorting to trailing metadata arguments. ([@cbliard]) - Replace `RSpec/StringAsInstanceDoubleConstant` with `RSpec/VerifiedDoubleReference` configured to only support constant class references. ([@corsonknowles]) - Fix `RSpec/EmptyExampleGroup` cop false positive when a simple conditional is used inside an iterator. ([@lovro-bikic]) ## 3.3.0 (2024-12-12) - Deprecate `top_level_group?` method from `TopLevelGroup` mixin as all of its callers were intentionally removed from `Rubocop/RSpec`. ([@corsonknowles]) - Fix false positive for RSpec/EmptyMetadata for splat kwargs. ([@pirj]) ## 3.2.0 (2024-10-26) - Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Add support for `and` and `or` compound matchers to `RSpec/ChangeByZero` cop. ([@ydah]) ## 3.1.0 (2024-10-01) - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) - Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) ## 3.0.5 (2024-09-07) - Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard]) - Improve offense message for `RSpec/IndexedLet`. ([@earlopain]) ## 3.0.4 (2024-08-05) - Fix false-negative for `UnspecifiedException` when matcher is chained. ([@r7kamura]) ## 3.0.3 (2024-07-12) - Add support for Unicode RIGHT SINGLE QUOTATION MARK in `RSpec/ExampleWording`. ([@jdufresne]) - Suppress deprecation warning for `RSpec/MultipleExpectations`, `RSpec/MultipleMemoizedHelpers`, and `RSpec/NestedGroups` cops. ([@koic]) ## 3.0.2 (2024-07-02) - Fix wrong autocorrect for `RSpec/ScatteredSetup` when hook contains heredoc. ([@earlopain]) - Fix false negative for `RSpec/PredicateMatcher` when expectation contains custom failure message. ([@earlopain]) - Facilitate the 3.0 upgrade flow with proper extracted cop messages. ([@jeppester]) ## 3.0.1 (2024-06-11) - Bump RuboCop requirement to +1.61. ([@ydah]) ## 3.0.0 (2024-06-11) - Remove extracted cops in `Capybara`, `FactoryBot` and `Rails` departments. ([@ydah]) - Remove `RuboCop::RSpec::Language::NodePattern`. ([@ydah]) - Remove `RSpec/FilePath` cop. ([@ydah]) - Remove `RSpec/Capybara/FeatureMethods` cop. If you are using this cop, change it to use `RSpec/Dialect`. ([@ydah]) - Add new `RSpec/MissingExpectationTargetMethod` cop. ([@krororo]) - Fix an error for `RSpec/ScatteredSetup` when one of the hooks is an empty block. ([@earlopain]) These previously pending cops are now enabled by default: `RSpec/BeEmpty`, `RSpec/BeEq`, `RSpec/BeNil`, `RSpec/ChangeByZero`, `RSpec/ClassCheck`, `RSpec/ContainExactly`, `RSpec/DuplicatedMetadata`, `RSpec/EmptyMetadata`, `RSpec/EmptyOutput`, `RSpec/Eq`, `RSpec/ExcessiveDocstringSpacing`, `RSpec/ExpectInLet`, `RSpec/IdenticalEqualityAssertion`, `RSpec/IndexedLet`, `RSpec/IsExpectedSpecify`, `RSpec/MatchArray`, `RSpec/MetadataStyle`, `RSpec/NoExpectationExample`, `RSpec/PendingWithoutReason`, `RSpec/ReceiveMessages`, `RSpec/RedundantAround`, `RSpec/RedundantPredicateMatcher`, `RSpec/RemoveConst`, `RSpec/RepeatedSubjectCall`, `RSpec/SkipBlockInsideExample`, `RSpec/SortMetadata`, `RSpec/SpecFilePathFormat`, `RSpec/SpecFilePathSuffix`, `RSpec/SubjectDeclaration`, `RSpec/UndescriptiveLiteralsDescription`, and `RSpec/VerifiedDoubleReference`. Read more about how to upgrade in https://docs.rubocop.org/rubocop-rspec/upgrade_to_version_3.html ## 2.31.0 (2024-06-07) - Support `AutoCorrect: contextual` option for LSP. ([@ydah]) ## 2.30.0 (2024-06-03) - Add new `RSpec/ExpectInLet` cop. ([@yasu551]) ## 2.29.2 (2024-05-02) - Fix beginless and endless range bug for RepeatedIncludeExample cop. ([@hasghari]) - Fix a false positive for `RSpec/RepeatedSubjectCall` when subject is used as argument to function call. ([@K-S-A]) ## 2.29.1 (2024-04-05) - Fix an error in the default configuration. ([@ydah]) ## 2.29.0 (2024-04-04) - Fix an autocorrect error for `RSpec/ExpectActual`. ([@bquorning]) - Add new `RSpec/UndescriptiveLiteralsDescription` cop. ([@ydah]) - Add new `RSpec/EmptyOutput` cop. ([@bquorning]) ## 2.28.0 (2024-03-30) - Extract RSpec Rails cops to a separate repository, [`rubocop-rspec_rails`](https://github.com/rubocop/rubocop-rspec_rails). The `rubocop-rspec_rails` repository is a dependency of `rubocop-rspec` and the cops related to rspec-rails are aliased (`RSpec/Rails/Foo` == `RSpecRails/Foo`) until v3.0 is released, so the change will be invisible to users until then. ([@ydah]) ## 2.27.1 (2024-03-03) - Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah]) - Add configuration option `OnlyStaticConstants` to `RSpec/DescribedClass`. ([@ydah]) ## 2.27.0 (2024-03-01) - Add new `RSpec/IsExpectedSpecify` cop. ([@ydah]) - Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet]) - Add support for `assert_true`, `assert_false`, `assert_not_equal`, `assert_not_nil`, `*_empty`, `*_predicate`, `*_kind_of`, `*_in_delta`, `*_match`, `*_instance_of` and `*_includes` assertions in `RSpec/Rails/MinitestAssertions`. ([@ydah], [@G-Rath]) - Support asserts with messages in `RSpec/BeEmpty`. ([@G-Rath]) - Fix a false positive for `RSpec/ExpectActual` when used with rspec-rails routing matchers. ([@naveg]) - Add configuration option `ResponseMethods` to `RSpec/Rails/HaveHttpStatus`. ([@ydah]) - Fix a false negative for `RSpec/DescribedClass` when class with constant. ([@ydah]) - Fix a false positive for `RSpec/ExampleWithoutDescription` when `specify` with multi-line block and missing description. ([@ydah]) - Fix an incorrect autocorrect for `RSpec/ChangeByZero` when compound expectations with line break before `.by(0)`. ([@ydah]) ## 2.26.1 (2024-01-05) - Fix an error for `RSpec/SharedExamples` when using examples without argument. ([@ydah]) ## 2.26.0 (2024-01-04) - Add new `RSpec/RedundantPredicateMatcher` cop. ([@ydah]) - Add new `RSpec/RemoveConst` cop. ([@swelther]) - Add support for correcting "it will" (future tense) for `RSpec/ExampleWording`. ([@jdufresne]) - Add support for `symbol` style for `RSpec/SharedExamples`. ([@jessieay]) - Ensure `PendingWithoutReason` can detect violations inside shared groups. ([@robinaugh]) ## 2.25.0 (2023-10-27) - Add support single quoted string and percent string and heredoc for `RSpec/Rails/HttpStatus`. ([@ydah]) - Change to be inline disable for `RSpec/SpecFilePathFormat` like `RSpec/FilePath`. ([@ydah]) - Fix a false positive for `RSpec/MetadataStyle` with example groups having multiple string arguments. ([@franzliedke]) ## 2.24.1 (2023-09-23) - Fix an error when using `RSpec/FilePath` and revert to enabled by default. If you have already moved to `RSpec/SpecFilePathSuffix` and `RSpec/SpecFilePathFormat`, disable `RSpec/FilePath` explicitly as `Enabled: false`. The `RSpec/FilePath` before migration and the `RSpec/SpecFilePathSuffix` and `RSpec/SpecFilePathFormat` as the target are available respectively. ([@ydah]) ## 2.24.0 (2023-09-08) - Split `RSpec/FilePath` into `RSpec/SpecFilePathSuffix` and `RSpec/SpecFilePathFormat`. `RSpec/FilePath` cop is disabled by default and the two new cops are pending and need to be enabled explicitly. ([@ydah]) - Add new `RSpec/Eq` cop. ([@ydah]) - Add `RSpec/MetadataStyle` and `RSpec/EmptyMetadata` cops. ([@r7kamura]) - Add support `RSpec/Rails/HttpStatus` when `have_http_status` with string argument. ([@ydah]) - Fix an infinite loop error when `RSpec/ExcessiveDocstringSpacing` finds a description with non-ASCII leading/trailing whitespace. ([@bcgraham]) - Fix an incorrect autocorrect for `RSpec/ReceiveMessages` when return values declared between stubs. ([@marocchino]) - Fix a false positive `RSpec/Focus` when chained method call and inside define method. ([@ydah]) ## 2.23.2 (2023-08-09) - Fix an incorrect autocorrect for `RSpec/ReceiveMessages` when method is only non-word character. ([@marocchino]) - Fix a false positive for `RSpec/ReceiveMessages` when return with splat. ([@marocchino]) ## 2.23.1 (2023-08-07) - Mark to `Safe: false` for `RSpec/Rails/NegationBeValid` cop. ([@ydah]) - Declare autocorrect as unsafe for `RSpec/ReceiveMessages`. ([@bquorning]) ## 2.23.0 (2023-07-30) - Add new `RSpec/Rails/NegationBeValid` cop. ([@ydah]) - Fix a false negative for `RSpec/ExcessiveDocstringSpacing` when finds description with em space. ([@ydah]) - Fix a false positive for `RSpec/EmptyExampleGroup` when example group with examples defined in `if` branch inside iterator. ([@ydah]) - Update the message output of `RSpec/ExpectActual` to include the word 'value'. ([@corydiamand]) - Fix a false negative for `RSpec/Pending` when `it` without body. ([@ydah]) - Add new `RSpec/ReceiveMessages` cop. ([@ydah]) - Change default.yml path to use `**/spec/*` instead of `spec/*`. ([@ydah]) - Add `AllowedIdentifiers` and `AllowedPatterns` configuration option to `RSpec/IndexedLet`. ([@ydah]) - Fix `RSpec/NamedSubject` when block has no body. ([@splattael]) - Fix `RSpec/LetBeforeExamples` autocorrect incompatible with `RSpec/ScatteredLet` autocorrect. ([@ydah]) - Update `RSpec/Focus` to support `shared_context` and `shared_examples`. ([@tmaier]) ## 2.22.0 (2023-05-06) - Extract factory_bot cops to a separate repository, [`rubocop-factory_bot`](https://github.com/rubocop/rubocop-factory_bot). The `rubocop-factory_bot` repository is a dependency of `rubocop-rspec` and the factory_bot cops are aliased (`RSpec/FactoryBot/Foo` == `FactoryBot/Foo`) until v3.0 is released, so the change will be invisible to users until then. ([@ydah]) ## 2.21.0 (2023-05-05) - Fix a false positive in `RSpec/IndexedLet` with suffixes after index-like numbers. ([@pirj]) - Fix an error for `RSpec/Rails/HaveHttpStatus` with comparison with strings containing non-numeric characters. ([@ydah]) - Fix an error for `RSpec/MatchArray` when `match_array` with no argument. ([@ydah]) - Add support `a_block_changing` and `changing` for `RSpec/ChangeByZero`. ([@ydah]) - Drop Ruby 2.6 support. ([@ydah]) ## 2.20.0 (2023-04-18) - Add new `RSpec/IndexedLet` cop. ([@dmitrytsepelev]) - Add new `RSpec/BeEmpty` cop. ([@ydah], [@bquorning]) - Add autocorrect support for `RSpec/ScatteredSetup`. ([@ydah]) - Add support `be_status` style for `RSpec/Rails/HttpStatus`. ([@ydah]) - Add support for shared example groups to `RSpec/EmptyLineAfterExampleGroup`. ([@pirj]) - Add support for `RSpec/HaveHttpStatus` when using `response.code`. ([@ydah]) - Fix order of expected and actual in correction for `RSpec/Rails/MinitestAssertions`. ([@mvz]) - Fix a false positive for `RSpec/DescribedClassModuleWrapping` when RSpec.describe numblock is nested within a module. ([@ydah]) - Fix a false positive for `RSpec/FactoryBot/ConsistentParenthesesStyle` inside `&&`, `||` and `:?` when `omit_parentheses` is on. ([@dmitrytsepelev]) - Fix a false positive for `RSpec/PendingWithoutReason` when pending/skip has a reason inside an example group. ([@ydah]) - Fix a false negative for `RSpec/RedundantAround` when redundant numblock `around`. ([@ydah]) - Change `RSpec/ContainExactly` to ignore calls with no arguments, and change `RSpec/MatchArray` to ignore calls with an empty array literal argument. ([@ydah], [@bquorning]) - Make `RSpec/MatchArray` and `RSpec/ContainExactly` pending. ([@ydah]) ## 2.19.0 (2023-03-06) - Fix a false positive for `RSpec/ContextWording` when context is interpolated string literal or execute string. ([@ydah]) - Fix a false positive for `RSpec/DescribeMethod` when multi-line describe without `#` and `.` at the beginning. ([@ydah], [@pirj]) - Fix a false positive for `RSpec/VariableName` when inside non-spec code. ([@ydah]) - Fix a false positive for `RSpec/VariableDefinition` when inside non-spec code. ([@ydah]) - Add new `RSpec/PendingBlockInsideExample` cop. ([@ydah]) - Add `RSpec/RedundantAround` cop. ([@r7kamura]) - Add `RSpec/Rails/TravelAround` cop. ([@r7kamura]) - Add `RSpec/ContainExactly` and `RSpec/MatchArray` cops. ([@faucct]) - Fix a false positive for `RSpec/PendingWithoutReason` when not inside example and pending/skip with block. ([@ydah], [@pirj]) - Fix a false positive for `RSpec/PendingWithoutReason` when `skip` is passed a block inside example. ([@ydah], [@pirj]) - Rename `RSpec/PendingBlockInsideExample` cop to `RSpec/SkipBlockInsideExample`. ([@pirj]) - Deprecate `send_pattern`/`block_pattern`/`numblock_pattern` helpers in favour of using node pattern explicitly. ([@pirj], [@ydah]) - Fix an incorrect autocorrect for `RSpec/VerifiedDoubleReference` when namespaced class. ([@ydah]) ## 2.18.1 (2023-01-19) - Add `rubocop-capybara` version constraint to prevent sudden cop enabling when it hits 3.0. ([@pirj]) ## 2.18.0 (2023-01-16) - Extract Capybara cops to a separate repository, [`rubocop-capybara`](https://github.com/rubocop/rubocop-capybara). The `rubocop-capybara` repository is a dependency of `rubocop-rspec` and the Capybara cops are aliased (`RSpec/Capybara/Foo` == `Capybara/Foo`) until v3.0 is released, so the change will be invisible to users until then. ([@pirj]) ## 2.17.1 (2023-01-16) - Fix a false negative for `RSpec/Pending` when using skipped in metadata is multiline string. ([@ydah]) - Fix a false positive for `RSpec/NoExpectationExample` when using skipped in metadata is multiline string. ([@ydah]) - Fix a false positive for `RSpec/ContextMethod` when multi-line context with `#` at the beginning. ([@ydah]) - Fix an incorrect autocorrect for `RSpec/PredicateMatcher` when multiline expect and predicate method with heredoc. ([@ydah]) - Fix a false positive for `RSpec/PredicateMatcher` when `include` with multiple argument. ([@ydah]) ## 2.17.0 (2023-01-13) - Fix a false positive for `RSpec/PendingWithoutReason` when pending/skip is argument of methods. ([@ydah]) - Add new `RSpec/Capybara/MatchStyle` cop. ([@ydah]) - Add new `RSpec/Rails/MinitestAssertions` cop. ([@ydah]) - Fix a false positive for `RSpec/PendingWithoutReason` when not inside example. ([@ydah]) - Fix a false negative for `RSpec/PredicateMatcher` when using `include` and `respond_to`. ([@ydah]) - Fix a false positive for `RSpec/StubbedMock` when stubbed message expectation with a block and block parameter. ([@ydah]) ## 2.16.0 (2022-12-13) - Add new `RSpec/FactoryBot/FactoryNameStyle` cop. ([@ydah]) - Improved processing speed for `RSpec/Be`, `RSpec/ExpectActual`, `RSpec/ImplicitExpect`, `RSpec/MessageSpies`, `RSpec/PredicateMatcher` and `RSpec/Rails/HaveHttpStatus`. ([@ydah]) - Fix wrong autocorrection in `n_times` style on `RSpec/FactoryBot/CreateList`. ([@r7kamura]) - Fix a false positive for `RSpec/FactoryBot/ConsistentParenthesesStyle` when using `generate` with multiple arguments. ([@ydah]) - Mark `RSpec/BeEq` as `Safe: false`. ([@r7kamura]) - Add `RSpec/DuplicatedMetadata` cop. ([@r7kamura]) - Mark `RSpec/BeEql` as `Safe: false`. ([@r7kamura]) - Add `RSpec/PendingWithoutReason` cop. ([@r7kamura]) ## 2.15.0 (2022-11-03) - Fix a false positive for `RSpec/RepeatedDescription` when different its block expectations are used. ([@ydah]) - Add `named_only` style to `RSpec/NamedSubject`. ([@kuahyeow]) - Fix `RSpec/FactoryBot/ConsistentParenthesesStyle` to ignore calls without the first positional argument. ([@pirj]) - Fix `RSpec/FactoryBot/ConsistentParenthesesStyle` to ignore calls inside a Hash or an Array. ([@pirj]) - Fix `RSpec/NestedGroups` to correctly use `AllowedGroups` config. ([@samrjenkins]) - Remove `Runners` and `HookScopes` RSpec DSL elements from configuration. ([@pirj]) - Add `with default RSpec/Language config` helper to `lib` (under `rubocop/rspec/shared_contexts/default_rspec_language_config_context`), to allow use for downstream cops based on `RuboCop::Cop::RSpec::Base`. ([@smcgivern]) ## 2.14.2 (2022-10-25) - Fix an incorrect autocorrect for `FactoryBot/ConsistentParenthesesStyle` with `omit_parentheses` option when method name and first argument are not on same line. ([@ydah]) - Fix autocorrection loop in `RSpec/ExampleWording` for insufficient example wording. ([@pirj]) - Fix `RSpec/SortMetadata` not to reorder arguments of `include_`/`it_behaves_like`. ([@pirj]) - Fix a false positive for `RSpec/NoExpectationExample` when allowed pattern methods with arguments. ([@ydah]) - Change `RSpec/FilePath` so that it only checks suffix when path is under spec/routing or type is defined as routing. ([@r7kamura]) ## 2.14.1 (2022-10-24) - Fix an error for `RSpec/Rails/InferredSpecType` with redundant type before other Hash metadata. ([@ydah]) ## 2.14.0 (2022-10-23) - Add `require_implicit` style to `RSpec/ImplicitSubject`. ([@r7kamura]) - Fix a false positive for `RSpec/Capybara/SpecificMatcher` when `have_css("a")` without attribute. ([@ydah]) - Update `RSpec/ExampleWording` cop to raise error for insufficient descriptions. ([@akrox58]) - Add new `RSpec/Capybara/NegationMatcher` cop. ([@ydah]) - Add `AllowedPatterns` configuration option to `RSpec/NoExpectationExample`. ([@ydah]) - Improve `RSpec/NoExpectationExample` cop to ignore examples skipped or pending via metadata. ([@pirj]) - Add `RSpec/FactoryBot/ConsistentParenthesesStyle` cop. ([@Liberatys]) - Add `RSpec/Rails/InferredSpecType` cop. ([@r7kamura]) - Add new `RSpec/Capybara/SpecificActions` cop. ([@ydah]) - Update `config/default.yml` removing deprecated option to make the config correctable by users. ([@ignaciovillaverde]) - Do not attempt to auto-correct example groups with `include_examples` in `RSpec/LetBeforeExamples`. ([@pirj]) - Add new `RSpec/SortMetadata` cop. ([@leoarnold]) - Add support for subject! method to `RSpec/SubjectDeclaration`. ([@ydah]) ## 2.13.2 (2022-09-23) - Fix an error for `RSpec/Capybara/SpecificFinders` with no parentheses. ([@ydah]) - Fix a false positive for `RSpec/NoExpectationExample` with pending using `skip` or `pending` inside an example. ([@ydah]) - Exclude `have_text` and `have_content` that raise `ArgumentError` with `RSpec/Capybara/VisibilityMatcher` where `:visible` is an invalid option. ([@ydah]) - Fix a false negative for `RSpec/Capybara/VisibilityMatcher` with negative matchers. ([@ydah]) ## 2.13.1 (2022-09-12) - Include config/obsoletion.yml in the gemspec. ([@hosamaly]) ## 2.13.0 (2022-09-12) - Fix `RSpec/FilePath` cop missing mismatched expanded namespace. ([@sl4vr]) - Add new `AllowConsecutiveOneLiners` (default true) option for `RSpec/EmptyLineAfterHook` cop. ([@ngouy]) - Add autocorrect support for `RSpec/EmptyExampleGroup`. ([@r7kamura]) - Fix `RSpec/ChangeByZero` with compound expressions using `&` or `|` operators. ([@BrianHawley]) - Add `RSpec/NoExpectationExample`. ([@r7kamura]) - Add some expectation methods to default configuration. ([@r7kamura]) - Fix a false positive for `RSpec/Capybara/SpecificMatcher`. ([@ydah]) - Fix a false negative for `RSpec/Capybara/SpecificMatcher` for `have_field`. ([@ydah]) - Fix a false positive for `RSpec/Capybara/SpecificMatcher` when may not have a `href` by `have_link`. ([@ydah]) - Add `NegatedMatcher` configuration option to `RSpec/ChangeByZero`. ([@ydah]) - Add new `RSpec/Capybara/SpecificFinders` cop. ([@ydah]) - Add support for numblocks to `RSpec/AroundBlock`, `RSpec/EmptyLineAfterHook`, `RSpec/ExpectInHook`, `RSpec/HookArgument`, `RSpec/HooksBeforeExamples`, `RSpec/IteratedExpectation`, and `RSpec/NoExpectationExample`. ([@ydah]) - Fix incorrect documentation URLs when using `rubocop --show-docs-url`. ([@r7kamura]) - Add `AllowedGroups` configuration option to `RSpec/NestedGroups`. ([@ydah]) - Deprecate `IgnoredPatterns` option in favor of the `AllowedPatterns` options. ([@ydah]) - Add `AllowedPatterns` configuration option to `RSpec/ContextWording`. ([@ydah]) - Add `RSpec/ClassCheck` cop. ([@r7kamura]) - Fix a false positive for `RSpec/Capybara/SpecificMatcher` when pseudo-classes. ([@ydah]) - Fix a false negative for `RSpec/SubjectStub` when the subject is declared with the `subject!` method and called by name. ([@eikes]) - Support `Array.new(n)` on `RSpec/FactoryBot/CreateList` cop. ([@r7kamura]) ## 2.12.1 (2022-07-03) - Fix a false positive for `RSpec/Capybara/SpecificMatcher`. ([@ydah]) ## 2.12.0 (2022-07-02) - Fix incorrect path suggested by `RSpec/FilePath` cop when second argument contains spaces. ([@tejasbubane]) - Fix autocorrect for EmptyLineSeparation. ([@johnny-miyake]) - Add new `RSpec/Capybara/SpecificMatcher` cop. ([@ydah]) - Fixed false offense detection in `FactoryBot/CreateList` when a n.times block is including method calls in the factory create arguments. ([@ngouy]) - Fix error in `RSpec/RSpec/FactoryBot/CreateList` cop for empty block. ([@tejasbubane]) - Update `RSpec/MultipleExpectations` cop documentation with examples of aggregate_failures use. ([@edgibbs]) - Declare autocorrect as unsafe for `RSpec/VerifiedDoubleReference`. ([@Drowze]) - Add new `RSpec/Rails/HaveHttpStatus` cop. ([@akiomik]) ## 2.11.1 (2022-05-18) - Fix a regression in `RSpec/ExpectChange` flagging chained method calls. ([@pirj]) ## 2.11.0 (2022-05-18) - Drop Ruby 2.5 support. ([@ydah]) - Add new `RSpec/ChangeByZero` cop. ([@ydah]) - Improve `RSpec/ExpectChange` to detect namespaced and top-level constants. ([@M-Yamashita01]) - Introduce an amendment to `Metrics/BlockLength` to exclude spec files. ([@luke-hill]) ## 2.10.0 (2022-04-19) - Fix a false positive for `RSpec/EmptyExampleGroup` when expectations in case statement. ([@ydah]) - Add `RSpec/VerifiedDoubleReference` cop. ([@t3h2mas]) - Make `RSpec/BeNil` cop configurable with a `be_nil` style and a `be` style. ([@bquorning]) - Fix `Capybara/CurrentPathExpectation` autocorrect incompatible with `Style/TrailingCommaInArguments` autocorrect. ([@ydah]) ## 2.9.0 (2022-02-28) - Add new `RSpec/BeNil` cop. ([@bquorning]) - Add new `RSpec/BeEq` cop. ([@bquorning]) ## 2.8.0 (2022-01-24) - Fix `RSpec/FactoryBot/SyntaxMethods` and `RSpec/Capybara/FeatureMethods` to inspect shared groups. ([@pirj]) - Fix `RSpec/LeadingSubject` failure in non-spec code. ([@pirj]) - Add bad example to `RSpec/SubjectStub` cop. ([@oshiro3]) - Replace non-styleguide cops `StyleGuide` attribute with `Reference`. ([@pirj]) - Fix `RSpec/SubjectStub` to disallow stubbing of subjects defined in parent example groups. ([@pirj]) ## 2.7.0 (2021-12-26) - Add new `RSpec/FactoryBot/SyntaxMethods` cop. ([@leoarnold]) - Exclude `task` type specs from `RSpec/DescribeClass` cop. ([@harry-graham]) ## 2.6.0 (2021-11-08) - Fix merging RSpec DSL configuration from third-party gems. ([@pirj]) - Fix `RSpec/ExcessiveDocstringSpacing` false positive for multi-line indented strings. ([@G-Rath]) - Fix `Include` configuration for sub-departments. ([@pirj]) - Ignore heredocs in `RSpec/ExcessiveDocstringSpacing`. ([@G-Rath]) - Stop `RSpec/ExampleWording` from trying to correct heredocs. ([@G-Rath]) - Add autocorrect support for `RSpec/VariableDefinition`. ([@r7kamura]) ## 2.5.0 (2021-09-21) - Declare autocorrect as unsafe for `ExpectChange`. ([@francois-ferrandis]) - Fix each example for `RSpec/HookArgument`. ([@lokhi]) - Exclude unrelated Rails directories from `RSpec/DescribeClass`. ([@MothOnMars]) - Add `RSpec/ExcessiveDocstringSpacing` cop. ([@G-Rath]) - Add `RSpec/SubjectDeclaration` cop. ([@dswij]) - Fix excessive whitespace removal in `RSpec/EmptyHook` autocorrection. ([@pirj]) - Bump RuboCop requirement to v1.19.0. ([@pirj]) - Fix false positive in `RSpec/IteratedExpectation` when there is single, non-expectation statement in the block body. ([@Darhazer]) ## 2.4.0 (2021-06-09) - Update `RSpec/FilePath` to check suffix when given a non-constant top-level node (e.g. features). ([@topalovic]) - Add missing documentation for `single_statement_only` style of `RSpec/ImplicitSubject` cop. ([@tejasbubane]) - Fix an exception in `DescribedClass` when accessing a constant on a variable in a spec that is nested in a namespace. ([@rrosenblum]) - Add new `RSpec/IdenticalEqualityAssertion` cop. ([@tejasbubane]) - Add `RSpec/Rails/AvoidSetupHook` cop. ([@paydaylight]) - Fix false negative in `RSpec/ExpectChange` cop with block style and chained method call. ([@tejasbubane]) ## 2.3.0 (2021-04-28) - Allow `RSpec/ContextWording` to accept multi-word prefixes. ([@hosamaly]) - Drop support for ruby 2.4. ([@bquorning]) - Add `CountAsOne` configuration option to `RSpec/ExampleLength`. ([@stephannv]) - Fix a false positive for `RSpec/RepeatedExampleGroupBody` when `pending` or `skip` have argument(s). ([@Tietew]) ## 2.2.0 (2021-02-02) - Fix `HooksBeforeExamples`, `LeadingSubject`, `LetBeforeExamples` and `ScatteredLet` autocorrection to take into account inline comments and comments immediately before the moved node. ([@Darhazer]) - Improve rubocop-rspec performance. ([@Darhazer], [@bquorning]) - Include `Enabled: true` to prevent a mismatched configuration parameter warning when `RSpec` cops are explicitly enabled in the user configuration. ([@pirj]) ## 2.1.0 (2020-12-17) - Fix `RSpec/FilePath` false positive for relative file path runs with long namespaces. ([@ahukkanen]) - Update `RSpec/Focus` to have auto-correction. ([@dvandersluis]) ## 2.0.1 (2020-12-02) - Fixed infinite loop in `RSpec/ExpectActual` autocorrection when both expected and actual values are literals. ([@Darhazer]) ## 2.0.0 (2020-11-06) - Remove deprecated class `::RuboCop::Cop::RSpec::Cop`. ([@bquorning]) - Retire `RSpec/InvalidPredicateMatcher` cop. ([@pirj]) - Remove the code responsible for filtering files to inspect. ([@pirj]) - Make RSpec language elements configurable. ([@sl4vr]) - Remove `CustomIncludeMethods` `RSpec/EmptyExampleGroup` option in favour of the new RSpec DSL configuration. ([@pirj]) - Enabled pending cop (`RSpec/StubbedMock`). ([@pirj]) ## 2.0.0.pre (2020-10-22) - Update RuboCop dependency to v1.0.0. ([@bquorning]) - Change namespace of several cops (`Capybara/*` -> `RSpec/Capybara/*`, `FactoryBot/*` -> `RSpec/FactoryBot/*`, `Rails/*` -> `RSpec/Rails/*`). ([@pirj], [@bquorning]) ## 1.44.1 (2020-10-20) - Relax `rubocop-ast` version constraint. ([@PhilCoggins]) ## 1.44.0 (2020-10-20) - Move our documentation from rubocop-rspec.readthedocs.io to docs.rubocop.org/rubocop-rspec. ([@bquorning]) - Add `RSpec/RepeatedIncludeExample` cop. ([@biinari]) - Add `RSpec/StubbedMock` cop. ([@bquorning], [@pirj]) - Add `IgnoredMetadata` configuration option to `RSpec/DescribeClass`. ([@Rafix02]) - Fix false positives in `RSpec/EmptyExampleGroup`. ([@pirj]) - Fix a false positive for `RSpec/EmptyExampleGroup` when example is defined in an `if` branch. ([@koic]) ## 1.43.2 (2020-08-25) - Fix `RSpec/FilePath` when checking a file with a shared example. ([@pirj]) - Fix subject nesting detection in `RSpec/LeadingSubject`. ([@pirj]) ## 1.43.1 (2020-08-17) - Fix `RSpec/FilePath` when checking a file defining e.g. an empty class. ([@bquorning]) ## 1.43.0 (2020-08-17) - Add a new base cop class `::RuboCop::Cop::RSpec::Base`. The old base class `::RuboCop::Cop::RSpec::Cop` is deprecated, and will be removed in the next major release. ([@bquorning]) - Add support for subject detection after includes and example groups in `RSpec/LeadingSubject`. ([@pirj]) - Ignore trailing punctuation in context description prefix. ([@elliterate]) - Relax `RSpec/VariableDefinition` cop so interpolated and multiline strings are accepted even when configured to enforce the `symbol` style. ([@bquorning]) - Fix `RSpec/EmptyExampleGroup` to flag example groups with examples in invalid scopes. ([@mlarraz]) - Fix `RSpec/EmptyExampleGroup` to ignore examples groups with examples defined inside iterators. ([@pirj]) - Improve `RSpec/NestedGroups`, `RSpec/FilePath`, `RSpec/DescribeMethod`, `RSpec/MultipleDescribes`, `RSpec/DescribeClass`'s top-level example group detection. ([@pirj]) - Add detection of `let!` with a block-pass or a string literal to `RSpec/LetSetup`. ([@pirj]) - Add `IgnoredPatterns` configuration option to `RSpec/VariableName`. ([@jtannas]) - Add `RSpec/MultipleMemoizedHelpers` cop. ([@mockdeep]) ## 1.42.0 (2020-07-09) - Update RuboCop dependency to 0.87.0 because of changes to internal APIs. ([@bquorning], [@Darhazer]) ## 1.41.0 (2020-07-03) - Extend the list of Rails spec types for `RSpec/DescribeClass`. ([@pirj]) - Fix `FactoryBot/AttributeDefinedStatically` to allow `#traits_for_enum` without a block. ([@harrylewis]) - Improve the performance of `FactoryBot/AttributeDefinedStatically`, `RSpec/InstanceVariable`, `RSpec/LetSetup`, `RSpec/NestedGroups` and `RSpec/ReturnFromStub`. ([@andrykonchin]) ## 1.40.0 (2020-06-11) - Add new `RSpec/VariableName` cop. ([@tejasbubane]) - Add new `RSpec/VariableDefinition` cop. ([@tejasbubane]) - Expand `Capybara/VisibilityMatcher` to support more than just `have_selector`. ([@twalpole]) - Add new `SpecSuffixOnly` option to `RSpec/FilePath` cop. ([@zdennis]) - Allow `RSpec/RepeatedExampleGroupBody` to differ only by described_class. ([@robotdana]) - Fix `RSpec/FilePath` detection across sibling directories. ([@rolfschmidt]) - Improve the performance of `RSpec/SubjectStub` by an order of magnitude. ([@andrykonchin]) ## 1.39.0 (2020-05-01) - Fix `RSpec/FilePath` detection when absolute path includes test subject. ([@eitoball]) - Add new `Capybara/VisibilityMatcher` cop. ([@aried3r]) - Ignore String constants by `RSpec/Describe`. ([@AlexWayfer]) - Drop support for ruby 2.3. ([@bquorning]) - Fix multiple cops to detect `let` with proc argument. ([@tejasbubane]) - Add autocorrect support for `RSpec/ScatteredLet`. ([@Darhazer]) - Add new `RSpec/EmptyHook` cop. ([@tejasbubane]) ## 1.38.1 (2020-02-15) - Fix `RSpec/RepeatedDescription` to detect descriptions with interpolation and methods. ([@lazycoder9]) ## 1.38.0 (2020-02-11) - Fix `RSpec/InstanceVariable` detection inside custom matchers. ([@pirj]) - Fix `RSpec/ScatteredSetup` to distinguish hooks with different metadata. ([@pirj]) - Add autocorrect support for `RSpec/ExpectActual` cop. ([@dduugg], [@pirj]) - Add `RSpec/RepeatedExampleGroupBody` cop. ([@lazycoder9]) - Add `RSpec/RepeatedExampleGroupDescription` cop. ([@lazycoder9]) - Add block name and other lines to `RSpec/ScatteredSetup` message. ([@elebow]) - Fix `RSpec/RepeatedDescription` to take into account example metadata. ([@lazycoder9]) ## 1.37.1 (2019-12-16) - Improve message and description of `FactoryBot/FactoryClassName`. ([@ybiquitous]) - Fix `FactoryBot/FactoryClassName` to ignore `Hash` and `OpenStruct`. ([@jfragoulis]) ## 1.37.0 (2019-11-25) - Implement `RSpec/DescribedClassModuleWrapping` to disallow RSpec statements within a module. ([@kellysutton]) - Fix documentation rake task to support RuboCop 0.75. ([@nickcampbell18]) - Fix `RSpec/SubjectStub` to detect implicit subjects stubbed. ([@QQism]) - Fix `RSpec/Pending` not flagging `skip` with string values. ([@pirj]) - Add `AllowedExplicitMatchers` config option for `RSpec/PredicateMatcher`. ([@mkrawc]) - Add `FactoryBot/FactoryClassName` cop. ([@jfragoulis]) ## 1.36.0 (2019-09-27) - Fix `RSpec/DescribedClass`'s error when `described_class` is used as part of a constant. ([@pirj]) - Fix `RSpec/ExampleWording` autocorrect of multi-line docstrings. ([@pirj]) - Add `RSpec/ContextMethod` cop, to detect method names in `context`. ([@geniou]) - Update RuboCop dependency to 0.68.1 with support for children matching node pattern syntax. ([@pirj]) - Add `RSpec/EmptyLineAfterExample` cop to check that there is an empty line after example blocks. ([@pirj]) - Fix `Capybara/CurrentPathExpectation` auto-corrector, to include option `ignore_query: true`. ([@onumis]) - Fix `RSpec/Focus` detecting mixed array/hash metadata. ([@dgollahon]) - Fix `RSpec/Focus` to also detect `pending` examples. ([@dgollahon]) ## 1.35.0 (2019-08-02) - Add `RSpec/ImplicitBlockExpectation` cop. ([@pirj]) ## 1.34.1 (2019-07-31) - Fix `RSpec/DescribedClass`'s error when a local variable is part of the namespace. ([@pirj]) ## 1.34.0 (2019-07-23) - Remove `AggregateFailuresByDefault` config option of `RSpec/MultipleExpectations`. ([@pirj]) - Add `RSpec/LeakyConstantDeclaration` cop. ([@jonatas], [@pirj]) - Improve `aggregate_failures` metadata detection of `RSpec/MultipleExpectations`. ([@pirj]) - Improve `RSpec/SubjectStub` detection and message. ([@pirj]) - Change message of `RSpec/LetSetup` cop to be more descriptive. ([@foton]) - Improve `RSpec/ExampleWording` to handle interpolated example messages. ([@nc-holodakg]) - Improve detection by allowing the use of `RSpec` as a top-level constant. ([@pirj]) - Fix `RSpec/DescribedClass`'s incorrect detection. ([@pirj]) - Improve `RSpec/DescribedClass`'s ability to detect inside modules and classes. ([@pirj]) ## 1.33.0 (2019-05-13) - Let `RSpec/DescribedClass` pass `Struct` instantiation closures. ([@schmijos]) - Fixed `RSpec/ContextWording` missing `context`s with metadata. ([@pirj]) - Fix `FactoryBot/AttributeDefinedStatically` not working with an explicit receiver. ([@composerinteralia]) - Add `RSpec/Dialect` enforces custom RSpec dialects. ([@gsamokovarov]) - Fix redundant blank lines in `RSpec/MultipleSubjects`'s autocorrect. ([@pirj]) - Drop support for ruby `2.2`. ([@bquorning]) ## 1.32.0 (2019-01-27) - Add `RSpec/Yield` cop, suggesting using the `and_yield` method when stubbing a method, accepting a block. ([@Darhazer]) - Fix `FactoryBot/CreateList` autocorrect crashing when the factory is called with a block=. ([@Darhazer]) - Fixed `RSpec/Focus` not flagging some cases of `RSpec.describe` with `focus: true`. ([@Darhazer]) - Fixed `RSpec/Pending` not flagging some cases of `RSpec.describe` with `:skip`. ([@Darhazer]) - Fix false positive in `RSpec/ReceiveCounts` when method name `exactly`, `at_least` or `at_most` is used along with `times`, without being an RSpec API. ([@Darhazer]) ## 1.31.0 (2019-01-02) - Add `IgnoreSharedExamples` option for `RSpec/NamedSubject`. ([@RST-J]) - Add autocorrect support for `Capybara/CurrentPathExpectation` cop. ([@ypresto]) - Add support for built-in `exists` matcher for `RSpec/PredicateMatcher` cop. ([@mkenyon]) - `SingleArgumentMessageChain` no longer reports an array as it's only argument as an offense. ([@Darhazer]) ## 1.30.1 (2018-11-01) - `FactoryBot/CreateList` now ignores `times` blocks with an argument. ([@Darhazer]) ## 1.30.0 (2018-10-08) - Add config to `RSpec/VerifiedDoubles` to enforcement of verification on unnamed doubles. ([@BrentWheeldon]) - Fix `FactoryBot/AttributeDefinedStatically` not working when there is a non-symbol key. ([@vzvu3k6k]) - Fix false positive in `RSpec/ImplicitSubject` when `is_expected` is used inside `its()` block. ([@Darhazer]) - Add `single_statement_only` style to `RSpec/ImplicitSubject` as a more relaxed alternative to `single_line_only`. ([@Darhazer]) - Add `RSpec/UnspecifiedException` as a default cop to encourage more-specific `expect{}.to raise_error(ExceptionType)`, or `raise_exception` style handling of exceptions. ([@daveworth]) ## 1.29.1 (2018-09-01) - Fix false negative in `FactoryBot/AttributeDefinedStatically` when attribute is defined on `self`. ([@Darhazer]) - `RSpec/FactoryBot` cops will now also inspect the `spec/factories.rb` path by default. ([@bquorning]) ## 1.29.0 (2018-08-25) - `RSpec/InstanceVariable` - Recommend local variables in addition to `let`. ([@jaredbeck]) - Add `RSpec/ImplicitSubject` cop. ([@Darhazer]) - Add `RSpec/HooksBeforeExamples` cop. ([@Darhazer]) ## 1.28.0 (2018-08-14) - Add `RSpec/ReceiveNever` cop enforcing usage of `not_to receive` instead of `never` matcher. ([@Darhazer]) - Fix false positive in `RSpec/EmptyLineAfterExampleGroup` cop when example is inside `if`. ([@Darhazer]) - Add `RSpec/MissingExampleGroupArgument` to enforce first argument for an example group. ([@geniou]) - Drop support for ruby `2.1`. ([@bquorning]) - Add `FactoryBot/AttributeDefinedStatically` cop to help FactoryBot users with the deprecation of static attributes. ([@composerinteralia], [@seanpdoyle]) - Remove `FactoryBot/DynamicAttributeDefinedStatically` and `FactoryBot/StaticAttributeDefinedDynamically` cops. ([@composerinteralia]) ## 1.27.0 (2018-06-14) - `RSpec/LeadingSubject` now enforces subject to be before any examples, hooks or let declarations. ([@Darhazer]) - Fix `RSpec/NotToNot` to highlight only the selector (`not_to` or `to_not`), so it works also on `expect { ... }` blocks. ([@bquorning]) - Add `RSpec/EmptyLineAfterHook` cop. ([@bquorning]) - Add `RSpec/EmptyLineAfterExampleGroup` cop to check that there is an empty line after example group blocks. ([@bquorning]) - Fix `RSpec/DescribeClass` crashing on `RSpec.describe` without arguments. ([@Darhazer]) - Bump RuboCop requirement to v0.56.0. ([@bquorning]) - Fix `RSpec/OverwritingSetup` crashing if a variable is used as an argument for `let`. ([@Darhazer]) ## 1.26.0 (2018-06-06) - Fix false positive in `RSpec/EmptyExampleGroup` cop when methods named like a RSpec method are used. ([@Darhazer]) - Fix `Capybara/FeatureMethods` not working when there is require before the spec. ([@Darhazer]) - Fix `RSpec/EmptyLineAfterFinalLet`: allow a comment to be placed after latest let, requiring empty line after the comment. ([@Darhazer]) - Add `RSpec/ReceiveCounts` cop to enforce usage of :once and :twice matchers. ([@Darhazer]) ## 1.25.1 (2018-04-10) - Fix false positive in `RSpec/Pending` cop when pending is used as a method name. ([@Darhazer]) - Fix `FactoryBot/DynamicAttributeDefinedStatically` false positive when using symbol proc argument for a sequence. ([@tdeo]) ## 1.25.0 (2018-04-07) - Add `RSpec/SharedExamples` cop to enforce consistent usage of string to titleize shared examples. ([@anthony-robin]) - Add `RSpec/Be` cop to enforce passing argument to the generic `be` matcher. ([@Darhazer]) - Fix false positives in `StaticAttributeDefinedDynamically` and `ReturnFromStub` when a const is used in an array or hash. ([@Darhazer]) - Add `RSpec/Pending` cop to enforce no existing pending or skipped examples. This is disabled by default. ([@patrickomatic]) - Fix `RSpec/NestedGroups` cop support --auto-gen-config. ([@walf443]) - Fix false positives in `Capybara/FeatureMethods` when feature methods are used as property names in a factory. ([@Darhazer]) - Allow configuring enabled methods in `Capybara/FeatureMethods`. ([@Darhazer]) - Add `FactoryBot/CreateList` cop. ([@Darhazer]) ## 1.24.0 (2018-03-06) - Compatibility with RuboCop v0.53.0. ([@bquorning]) - The `Rails/HttpStatus` cop is unavailable if the `rack` gem cannot be loaded. ([@bquorning]) - Fix `Rails/HttpStatus` not working with custom HTTP status codes. ([@bquorning]) - Fix `FactoryBot/StaticAttributeDefinedDynamically` to handle empty block. ([@abrom]) - Fix false positive in `FactoryBot/DynamicAttributeDefinedStatically` when a before/after callback has a symbol proc argument. ([@abrom]) ## 1.23.0 (2018-02-23) - Add `RSpec/Rails/HttpStatus` cop to enforce consistent usage of the status format (numeric or symbolic). ([@anthony-robin], [@jojos003]) - Fix false negative in `RSpec/ReturnFromStub` when a constant is being returned by the stub. ([@Darhazer]) - Fix `FactoryBot/DynamicAttributeDefinedStatically` to handle dynamic attributes inside arrays/hashes. ([@abrom]) - Add `FactoryBot/StaticAttributeDefinedDynamically` (based on dynamic attribute cop). ([@abrom]) ## 1.22.2 (2018-02-01) - Fix error in `RSpec/DescribedClass` when working on an empty `describe` block. ([@bquorning]) ## 1.22.1 (2018-01-17) - Fix false positives in `RSpec/ReturnFromStub`. ([@Darhazer]) ## 1.22.0 (2018-01-10) - Updates `describe_class` to account for RSpecs `:system` wrapper of rails system tests. ([@EliseFitz15]) - Add `RSpec/ExpectChange` cop to enforce consistent usage of the change matcher. ([@Darhazer]) - Add autocorrect support to `RSpec/LetBeforeExamples`. ([@Darhazer]) - Fix `RSpec/InstanceVariable` flagging instance variables inside dynamically defined class. ([@Darhazer]) - Add autocorrect support for `RSpec/ReturnFromStub` cop. ([@bquorning]) - Add `RSpec/ExampleWithoutDescription` cop. ([@Darhazer]) ## 1.21.0 (2017-12-13) - Compatibility with RuboCop v0.52.0. ([@bquorning]) - Improve performance when user does not override default RSpec Pattern config. ([@walf443]) - Add `AggregateFailuresByDefault` configuration for `RSpec/MultipleExpectations` cop. ([@onk]) ## 1.20.1 (2017-11-15) - Add "without" to list of default allowed prefixes for `RSpec/ContextWording`. ([@bquorning]) ## 1.20.0 (2017-11-09) - Rename namespace `FactoryGirl` to `FactoryBot` following original library update. ([@walf443]) - Fix exception in `RSpec/ReturnFromStub` on empty block. ([@yevhene]) - Add `RSpec/ContextWording` cop. ([@pirj], [@telmofcosta]) - Fix `RSpec/SubjectStub` cop matches receive message inside all matcher. ([@walf443]) ## 1.19.0 (2017-10-18) Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. ## 1.18.0 (2017-09-29) - Fix false positive in `Capybara/FeatureMethods`. ([@Darhazer]) - Add `RSpec/Capybara/CurrentPathExpectation` cop for feature specs, disallowing setting expectations on `current_path`. ([@timrogers]) - Fix false positive in `RSpec/LetBeforeExamples` cop when example group contains single let. ([@Darhazer]) ## 1.17.1 (2017-09-20) - Improved `RSpec/ReturnFromStub` to handle string interpolation, hashes and do..end blocks. ([@Darhazer]) - Fixed compatibility with JRuby. ([@zverok]) ## 1.17.0 (2017-09-14) - Add `RSpec/Capybara` namespace including the first cop for feature specs: `Capybara/FeatureMethods`. ([@rspeicher]) - Update to RuboCop 0.50.0. ([@bquorning]) ## 1.16.0 (2017-09-06) - Add `RSpec/FactoryGirl` namespace including the first cop for factories: `FactoryGirl/DynamicAttributeDefinedStatically`. ([@jonatas]) - Add disabled by default `RSpec/AlignLeftLetBrace`. ([@backus]) - Add disabled by default `RSpec/AlignRightLetBrace`. ([@backus]) - Add `RSpec/LetBeforeExamples` cop. ([@Darhazer]) - Add `RSpec/MultipleSubjects` cop. ([@backus]) - Add `RSpec/ReturnFromStub` cop. ([@Darhazer]) - Add `RSpec/VoidExpect` cop. ([@pocke]) - Add `RSpec/InvalidPredicateMatcher` cop. ([@pocke]) - Change HookArgument cop to detect when hook has a receiver. ([@pocke]) - Add `RSpec/PredicateMatcher` cop. ([@pocke]) - Add `RSpec/ExpectInHook` cop. ([@pocke]) - `RSpec/MultipleExpectations` now detects usage of expect_any_instance_of. ([@Darhazer]) - `RSpec/MultipleExpectations` now detects usage of is_expected. ([@bmorrall]) ## 1.15.1 (2017-04-30) - Fix the handling of various edge cases in the `RSpec/ExampleWording` cop, including one that would cause autocorrect to crash. ([@dgollahon]) - Fix `RSpec/IteratedExpectation` crashing when there is an assignment in the iteration. ([@Darhazer]) - Fix false positive in `RSpec/SingleArgumentMessageChain` cop when the single argument is a hash. ([@Darhazer]) ## 1.15.0 (2017-03-24) - Add `RSpec/DescribeSymbol` cop. ([@rspeicher]) - Fix error when `RSpec/OverwritingSetup` and `RSpec/ScatteredLet` analyzed empty example groups. ([@backus]) ## 1.14.0 (2017-03-24) - Add `RSpec/OverwritingSetup` cop. ([@Darhazer]) - Add autocorrect support for `RSpec/LeadingSubject` cop. ([@Darhazer]) - Add `RSpec/ScatteredLet` cop. ([@Darhazer]) - Add `RSpec/IteratedExpectation` cop. ([@Darhazer]) - Add `RSpec/EmptyLineAfterSubject` cop. ([@Darhazer]) - Add `RSpec/EmptyLineAfterFinalLet` cop. ([@Darhazer]) ## 1.13.0 (2017-03-07) - Add repeated 'it' detection to `RSpec/ExampleWording` cop. ([@dgollahon]) - Add [observed_nesting/max_nesting] info to `RSpec/NestedGroups` messages. ([@dgollahon]) - Add `RSpec/ItBehavesLike` cop. ([@dgollahon]) - Add `RSpec/SharedContext` cop. ([@Darhazer]) - `RSpec/MultipleExpectations`: Count aggregate_failures block as single expectation. ([@Darhazer]) - Fix `ExpectActual` cop flagging `rspec-rails` routing specs. ([@backus]) - Fix `FilePath` cop not registering offenses for files like `spec/blog/user.rb` when it should be `spec/blog/user_spec.rb`. ([@backus]) ## 1.12.0 (2017-02-21) - Add `RSpec/InstanceSpy` cop. ([@Darhazer]) - Add `RSpec/BeforeAfterAll` for avoiding leaky global test setup. ([@cfabianski]) ## 1.11.0 (2017-02-16) - Add `AroundBlock` cop. ([@Darhazer]) - Add `EnforcedStyle` configuration for `RSpec/DescribedClass` cop. ([@Darhazer]) - Fix false positive for `RSpec/RepeatedExample` cop. ([@redross]) ## 1.10.0 (2017-01-15) - Fix false negative for `RSpec/MessageSpies` cop. ([@onk]) - Fix internal dependencies on RuboCop to be compatible with 0.47 release. ([@backus]) - Add autocorrect support for `SingleArgumentMessageChain` cop. ([@bquorning]) - Rename `NestedGroups`' configuration key from `MaxNesting` to `Max` in order to be consistent with other cop configuration. ([@backus]) - Add `RepeatedExample` cop for detecting repeated examples within example groups. ([@backus]) - Add `ScatteredSetup` cop for enforcing that only one `before`, `around`, and `after` hook are used per example group scope. ([@backus]) - Add `ExpectOutput` cop for recommending `expect { ... }.to output(...).to_stdout`. ([@backus]) ## 1.9.1 (2017-01-02) - Fix unintentional regression change in `NestedGroups` reported in #270. ([@backus]) - Change `MaxNesting` for `NestedGroups` from 2 to 3. ([@backus]) ## 1.9.0 (2016-12-29) - Add `MessageSpies` cop for enforcing consistent style of either `expect(...).to have_received` or `expect(...).to receive`, intended as a replacement for the `MessageExpectation` cop. ([@bquorning]) - Fix `DescribeClass` to not flag `describe` at the top of a block of shared examples. ([@clupprich]) - Add `SingleArgumentMessageChain` cop for recommending use of `receive` instead of `receive_message_chain` where possible. ([@bquorning]) - Add `RepeatedDescription` cop for detecting repeated example descriptions within example groups. ([@backus]) ## 1.8.0 (2016-10-27) - Optionally ignore method names in the `describe` argument when running the `FilePath` cop. ([@bquorning]) - Fix regression in how `FilePath` converts alphanumeric class names into paths. ([@bquorning]) - Add `ImplicitExpect` cop for enforcing `should` vs. `is_expected.to`. ([@backus]) - Disable `MessageExpectation` cop in the default configuration. ([@bquorning]) ## 1.7.0 (2016-08-24) - Add support for checking all example groups with `ExampleLength`. ([@backus]) - Add support for checking shared example groups for `DescribedClass`. ([@backus]) - Add support for checking `its` from [rspec-its](https://github.com/rspec/rspec-its). ([@backus]) - Add `EmptyExampleGroup` cop for detecting `describe`s and `context`s without any tests inside. ([@backus]) - Add `CustomIncludeMethods` configuration option for `EmptyExampleGroup`. ([@backus]) - Add `NestedGroups` cop for detecting excessive example group nesting. ([@backus]) - Add `MaxNesting` configuration option for `NestedGroups` cop. ([@backus]) - Add `ExpectActual` cop for detecting literal values within `expect(...)`. ([@backus]) - Add `MultipleExpectations` cop for detecting multiple `expect(...)` calls within one example. ([@backus]) - Add `Max` configuration option for `MultipleExpectations`. ([@backus]) - Add `SubjectStub` cop for testing stubbed test subjects. ([@backus]) - Add `LetSetup` cop for detecting cases where `let!` is used for test setup. ([@backus]) - Change all cops to only inspect files with names following rspec convention (`*/spec/*` and/or `_spec.rb`). ([@backus]) - Add `AllCops/RSpec` configuration option for specifying custom spec file patterns. ([@backus]) - Add `AssignmentOnly` configuration option for `RSpec/InstanceVariable` cop. ([@backus]) - Add `BeEql` cop which looks for expectations that can use `be(...)` instead of `eql(...)`. ([@backus]) - Add autocorrect support for `BeEql` cop. ([@backus]) - Add `MessageExpectation` cop for enforcing consistent style of either `expect(...).to receive` or `allow(...).to receive`. ([@backus]) - Add `MessageChain` cop. ([@bquorning]) ## 1.6.0 (2016-08-03) - Add `SkipBlocks` option for `DescribedClass` cop. ([@backus]) ## 1.5.3 (2016-08-02) - Add `RSpec/NamedSubject` cop. ([@backus]) ## 1.5.2 (2016-08-01) - Drop support for ruby `2.0.0` and `2.1.0`. ([@backus]) - Internal refactorings and improved test coverage. ([@backus]) ## 1.5.1 (2016-07-20) - Fix `unrecognized parameter RSpec/VerifiedDoubles:IgnoreSymbolicNames` warning. ([@jeffreyc]) - Update to rubocop 0.41.2. ([@backus]) ## 1.5.0 (2016-05-17) - Expand `VerifiedDoubles` cop to check for `spy` as well as `double`. ([@andyw8]) - Enable `VerifiedDoubles` cop by default. ([@andyw8]) - Add `IgnoreSymbolicNames` option for `VerifiedDoubles` cop. ([@andyw8]) - Add `RSpec::ExampleLength` cop. ([@andyw8]) - Handle alphanumeric class names in `FilePath` cop. ([@andyw8]) - Skip `DescribeClass` cop for view specs. ([@andyw8]) - Skip `FilePath` cop for Rails routing specs. ([@andyw8]) - Add cop to check for focused specs. ([@renanborgescampos], [@jaredmoody]) - Clean-up `RSpec::NotToNot` to use same configuration semantics as other RuboCop cops, add autocorrect support for `RSpec::NotToNot`. ([@baberthal]) - Update to rubocop 0.40.0. ([@nijikon]) ## 1.4.1 (2016-04-03) - Ignore routing specs for DescribeClass cop. ([@nijikon]) - Move rubocop dependency to runtime. ([@nijikon]) - Update to rubocop 0.39.0. ([@nijikon]) ## 1.4.0 (2016-02-15) - Update to rubocop 0.37.2. ([@nijikon]) - Update ruby versions we test against. ([@nijikon]) - Add `RSpec::NotToNot` cop. ([@miguelfteixeira]) - Add `RSpec/AnyInstance` cop. ([@mlarraz]) ## 1.3.1 - Fix auto correction issue - syntax had changed in RuboCop v0.31. ([@bquorning]) - Add RuboCop clone to vendor folder - see #39 for details. ([@bquorning]) ## 1.3.0 - Ignore non string arguments for FilePathCop - thanks to @deivid-rodriguez. ([@geniou]) - Skip DescribeMethod cop for tagged specs. ([@deivid-rodriguez]) - Skip DescribeClass cop for feature/request specs. ([@deivid-rodriguez]) ## 1.2.2 - Make `RSpec::ExampleWording` case insensitive. ([@geniou]) ## 1.2.1 - Add `RSpec::VerifiedDoubles` cop. ([@andyw8]) ## 1.2.0 - Drop support of ruby `1.9.2`. ([@geniou]) - Update to RuboCop `~> 0.24`. ([@geniou]) - Add `autocorrect` to `RSpec::ExampleWording`. This experimental - use with care and check the changes. ([@geniou]) - Fix config loader debug output. ([@geniou]) - Rename `FileName` cop to `FilePath` as a workaround - see [#19](https://github.com/nevir/rubocop-rspec/issues/19). ([@geniou]) ## 1.1.0 - Add `autocorrect` to `RSpec::DescribedClass` cop. ([@geniou]) ## 1.0.1 - Add `config` folder to gemspec. ([@pstengel]) ## 1.0.rc3 - Update to RuboCop `>= 0.23`. ([@geniou]) - Add configuration option for `CustomTransformation` to `FileName` cop. ([@geniou]) ## 1.0.rc2 - Gem is no longer 20MB (sorry!). ([@nevir]) - `RspecFileName` cop allows for method specs to organized into directories by class and type. ([@nevir]) ## 1.0.rc1 - Update code to work with rubocop `>= 0.19`. ([@geniou]) - Split `UnitSpecNaming` cop into `RSpecDescribeClass`, `RSpecDescribeMethod` and `RSpecFileName` and enabled them all by default. ([@geniou]) - Add `RSpecExampleWording` cop to prevent to use of should at the beginning of the spec description. ([@geniou]) - Fix `RSpecFileName` cop for non-class specs. ([@geniou]) - Adapt `RSpecFileName` cop to common naming convention and skip spec with multiple top level describes. ([@geniou]) - Add `RSpecMultipleDescribes` cop to check for multiple top level describes. ([@geniou]) - Add `RSpecDescribedClass` to promote the use of `described_class`. ([@geniou]) - Add `RSpecInstanceVariable` cop to check for the usage of instance variables. ([@geniou]) [@aarestad]: https://github.com/aarestad [@abrom]: https://github.com/abrom [@ahukkanen]: https://github.com/ahukkanen [@akiomik]: https://github.com/akiomik [@akrox58]: https://github.com/akrox58 [@alexwayfer]: https://github.com/AlexWayfer [@andrykonchin]: https://github.com/andrykonchin [@andyw8]: https://github.com/andyw8 [@anthony-robin]: https://github.com/anthony-robin [@aried3r]: https://github.com/aried3r [@baberthal]: https://github.com/baberthal [@backus]: https://github.com/backus [@bcgraham]: https://github.com/bcgraham [@biinari]: https://github.com/biinari [@bmorrall]: https://github.com/bmorrall [@bquorning]: https://github.com/bquorning [@brentwheeldon]: https://github.com/BrentWheeldon [@brianhawley]: https://github.com/BrianHawley [@cbliard]: https://github.com/cbliard [@cfabianski]: https://github.com/cfabianski [@clupprich]: https://github.com/clupprich [@composerinteralia]: https://github.com/composerinteralia [@corsonknowles]: https://github.com/corsonknowles [@corydiamand]: https://github.com/corydiamand [@d4rky-pl]: https://github.com/d4rky-pl [@darhazer]: https://github.com/Darhazer [@daveworth]: https://github.com/daveworth [@dduugg]: https://github.com/dduugg [@deivid-rodriguez]: https://github.com/deivid-rodriguez [@dgollahon]: https://github.com/dgollahon [@dmitrytsepelev]: https://github.com/dmitrytsepelev [@drcapulet]: https://github.com/drcapulet [@drowze]: https://github.com/Drowze [@dswij]: https://github.com/dswij [@dvandersluis]: https://github.com/dvandersluis [@earlopain]: https://github.com/earlopain [@edgibbs]: https://github.com/edgibbs [@eikes]: https://github.com/eikes [@eitoball]: https://github.com/eitoball [@elebow]: https://github.com/elebow [@elisefitz15]: https://github.com/EliseFitz15 [@elliterate]: https://github.com/elliterate [@faucct]: https://github.com/faucct [@foton]: https://github.com/foton [@francois-ferrandis]: https://github.com/francois-ferrandis [@franzliedke]: https://github.com/franzliedke [@g-rath]: https://github.com/G-Rath [@geniou]: https://github.com/geniou [@gsamokovarov]: https://github.com/gsamokovarov [@harry-graham]: https://github.com/harry-graham [@harrylewis]: https://github.com/harrylewis [@hasghari]: https://github.com/hasghari [@hosamaly]: https://github.com/hosamaly [@ignaciovillaverde]: https://github.com/ignaciovillaverde [@jaredbeck]: https://github.com/jaredbeck [@jaredmoody]: https://github.com/jaredmoody [@jdufresne]: https://github.com/jdufresne [@jeffreyc]: https://github.com/jeffreyc [@jeppester]: https://github.com/jeppester [@jessieay]: https://github.com/jessieay [@jfragoulis]: https://github.com/jfragoulis [@johnny-miyake]: https://github.com/johnny-miyake [@jojos003]: https://github.com/jojos003 [@jonatas]: https://github.com/jonatas [@jtannas]: https://github.com/jtannas [@k-s-a]: https://github.com/K-S-A [@kellysutton]: https://github.com/kellysutton [@kevinrobell-st]: https://github.com/kevinrobell-st [@koic]: https://github.com/koic [@krororo]: https://github.com/krororo [@kuahyeow]: https://github.com/kuahyeow [@lazycoder9]: https://github.com/lazycoder9 [@lee266]: https://github.com/lee266 [@leoarnold]: https://github.com/leoarnold [@liberatys]: https://github.com/Liberatys [@lokhi]: https://github.com/lokhi [@lovro-bikic]: https://github.com/lovro-bikic [@luke-hill]: https://github.com/luke-hill [@m-yamashita01]: https://github.com/M-Yamashita01 [@marocchino]: https://github.com/marocchino [@miguelfteixeira]: https://github.com/miguelfteixeira [@mkenyon]: https://github.com/mkenyon [@mkrawc]: https://github.com/mkrawc [@mlarraz]: https://github.com/mlarraz [@mockdeep]: https://github.com/mockdeep [@mothonmars]: https://github.com/MothOnMars [@mth0158]: https://github.com/Mth0158 [@mvz]: https://github.com/mvz [@naveg]: https://github.com/naveg [@nc-holodakg]: https://github.com/nc-holodakg [@nevir]: https://github.com/nevir [@ngouy]: https://github.com/ngouy [@nickcampbell18]: https://github.com/nickcampbell18 [@nijikon]: https://github.com/nijikon [@onk]: https://github.com/onk [@onumis]: https://github.com/onumis [@oshiro3]: https://github.com/oshiro3 [@patrickomatic]: https://github.com/patrickomatic [@paydaylight]: https://github.com/paydaylight [@philcoggins]: https://github.com/PhilCoggins [@pirj]: https://github.com/pirj [@pocke]: https://github.com/pocke [@pstengel]: https://github.com/pstengel [@qqism]: https://github.com/QQism [@r7kamura]: https://github.com/r7kamura [@rafix02]: https://github.com/Rafix02 [@redross]: https://github.com/redross [@renanborgescampos]: https://github.com/renanborgescampos [@robinaugh]: https://github.com/robinaugh [@robotdana]: https://github.com/robotdana [@rolfschmidt]: https://github.com/rolfschmidt [@rrosenblum]: https://github.com/rrosenblum [@rspeicher]: https://github.com/rspeicher [@rst-j]: https://github.com/RST-J [@sakuro]: https://github.com/sakuro [@samrjenkins]: https://github.com/samrjenkins [@schmijos]: https://github.com/schmijos [@seanpdoyle]: https://github.com/seanpdoyle [@sl4vr]: https://github.com/sl4vr [@smcgivern]: https://github.com/smcgivern [@splattael]: https://github.com/splattael [@stephannv]: https://github.com/stephannv [@sucicfilip]: https://github.com/sucicfilip [@swelther]: https://github.com/swelther [@t3h2mas]: https://github.com/t3h2mas [@tdeo]: https://github.com/tdeo [@tejasbubane]: https://github.com/tejasbubane [@telmofcosta]: https://github.com/telmofcosta [@tietew]: https://github.com/Tietew [@timrogers]: https://github.com/timrogers [@tmaier]: https://github.com/tmaier [@topalovic]: https://github.com/topalovic [@twalpole]: https://github.com/twalpole [@ushi-as]: https://github.com/ushi-as [@vzvu3k6k]: https://github.com/vzvu3k6k [@walf443]: https://github.com/walf443 [@yasu551]: https://github.com/yasu551 [@ybiquitous]: https://github.com/ybiquitous [@ydah]: https://github.com/ydah [@yevhene]: https://github.com/yevhene [@ypresto]: https://github.com/ypresto [@yujideveloper]: https://github.com/yujideveloper [@zdennis]: https://github.com/zdennis [@zverok]: https://github.com/zverok rubocop-rubocop-rspec-a5aeb29/CODE_OF_CONDUCT.md000066400000000000000000000015711512756157400212560ustar00rootroot00000000000000# The RuboCop Community Code of Conduct **Note:** We have picked the following code of conduct based on [Ruby's own code of conduct](https://www.ruby-lang.org/en/conduct/). This document provides a few simple community guidelines for a safe, respectful, productive, and collaborative place for any person who is willing to contribute to the RuboCop community. It applies to all "collaborative spaces", which are defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). - Participants will be tolerant of opposing views. - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. - When interpreting the words and actions of others, participants should always assume good intentions. - Behaviour which can be reasonably considered harassment will not be tolerated. rubocop-rubocop-rspec-a5aeb29/Gemfile000066400000000000000000000010021512756157400177370ustar00rootroot00000000000000# frozen_string_literal: true source 'https://rubygems.org' gemspec gem 'bump' gem 'irb' # undeclared dependency of yard gem 'rack' gem 'rake' gem 'rspec', '~> 3.11' gem 'rubocop-performance', '~> 1.24' gem 'rubocop-rake', '~> 0.7' gem 'simplecov', '>= 0.19' gem 'yard' # FIXME: Remove when the next prism version is released. if RUBY_VERSION < '3.0' || RUBY_ENGINE == 'jruby' gem 'prism', '!= 1.5.0', '!= 1.5.1' end local_gemfile = 'Gemfile.local' eval_gemfile(local_gemfile) if File.exist?(local_gemfile) rubocop-rubocop-rspec-a5aeb29/MIT-LICENSE.md000066400000000000000000000021101512756157400205000ustar00rootroot00000000000000# The MIT License (MIT) Copyright (c) 2014 Ian MacLeod Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rubocop-rubocop-rspec-a5aeb29/README.md000066400000000000000000000054571512756157400177450ustar00rootroot00000000000000# RuboCop RSpec [![Join the chat at https://gitter.im/rubocop-rspec/Lobby](https://badges.gitter.im/rubocop-rspec/Lobby.svg)](https://gitter.im/rubocop-rspec/Lobby) [![Gem Version](https://badge.fury.io/rb/rubocop-rspec.svg)](https://rubygems.org/gems/rubocop-rspec) ![CI](https://github.com/rubocop/rubocop-rspec/workflows/CI/badge.svg) [RSpec](https://rspec.info/)-specific analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop/rubocop). - [Installation](#installation) - [Upgrading to RuboCop RSpec v3.x](#upgrading-to-rubocop-rspec-v3x) - [Upgrading to RuboCop RSpec v2.x](#upgrading-to-rubocop-rspec-v2x) - [Usage](#usage) - [Documentation](#documentation) - [The Cops](#the-cops) - [Contributing](#contributing) - [License](#license) ## Installation Just install the `rubocop-rspec` gem ```bash gem install rubocop-rspec ``` or if you use bundler put this in your `Gemfile` ```ruby gem 'rubocop-rspec', require: false ``` ### Upgrading to RuboCop RSpec v3.x Read all the details in our [Upgrade to Version 3.x](https://docs.rubocop.org/rubocop-rspec/3.0/upgrade_to_version_3.html) document. ### Upgrading to RuboCop RSpec v2.x Read all the details in our [Upgrade to Version 2.x](https://docs.rubocop.org/rubocop-rspec/2.0/upgrade_to_version_2.html) document. ## Usage You need to tell RuboCop to load the RSpec extension. There are three ways to do this: ### RuboCop configuration file Put this into your `.rubocop.yml`. ```yaml plugins: rubocop-rspec ``` Alternatively, use the following array notation when specifying multiple extensions. ```yaml plugins: - rubocop-other-extension - rubocop-rspec ``` Now you can run `rubocop` and it will automatically load the RuboCop RSpec cops together with the standard cops. > [!NOTE] > The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`. ### Command line ```bash rubocop --plugin rubocop-rspec ``` ### Rake task ```ruby RuboCop::RakeTask.new do |task| task.plugins << 'rubocop-rspec' end ``` ### Code Climate rubocop-rspec is available on Code Climate as part of the rubocop engine. [Learn More](https://marketing.codeclimate.com/changelog/55a433bbe30ba00852000fac/). ## Documentation You can read more about RuboCop RSpec in its [official manual](https://docs.rubocop.org/rubocop-rspec). ## The Cops All cops are located under [`lib/rubocop/cop/rspec`](lib/rubocop/cop/rspec), and contain examples/documentation. In your `.rubocop.yml`, you may treat the RSpec cops just like any other cop. For example: ```yaml RSpec/SpecFilePathFormat: Exclude: - spec/my_poorly_named_spec_file.rb ``` ## Contributing Checkout the [contribution guidelines](.github/CONTRIBUTING.md). ## License `rubocop-rspec` is MIT licensed. [See the accompanying file](MIT-LICENSE.md) for the full text. rubocop-rubocop-rspec-a5aeb29/Rakefile000066400000000000000000000061721512756157400201260ustar00rootroot00000000000000# frozen_string_literal: true require 'open3' require 'bundler' require 'bundler/gem_tasks' begin Bundler.setup(:default, :development) rescue Bundler::BundlerError => e warn e.message warn 'Run `bundle install` to install missing gems' exit e.status_code end require 'rspec/core/rake_task' require 'rubocop/rake_task' Dir['tasks/**/*.rake'].each { |t| load t } RSpec::Core::RakeTask.new(:spec) do |spec| spec.pattern = FileList['spec/**/*_spec.rb'] end desc 'Run RuboCop over this gem' RuboCop::RakeTask.new(:internal_investigation) desc 'Build config/default.yml' task :build_config do require 'yard' require 'rubocop-rspec' require 'rubocop/rspec/config_formatter' require 'rubocop/rspec/description_extractor' glob = File.join('lib', 'rubocop', 'cop', 'rspec', '*.rb') # Due to YARD's sensitivity to file require order (as of 0.9.25), # we have to prepend the list with our base cop, RuboCop::Cop::RSpec::Base. # Otherwise, cop's parent class for cops loaded before our base cop class # are detected as RuboCop::Cop::Base, and that complicates the detection # of their relation with RuboCop RSpec. rspec_cop_path = File.join('lib', 'rubocop', 'cop', 'rspec', 'base.rb') YARD::Tags::Library.define_tag('Cop Safety Information', :safety) YARD.parse(Dir[glob].prepend(rspec_cop_path), []) descriptions = RuboCop::RSpec::DescriptionExtractor.new(YARD::Registry.all(:class)).to_h current_config = if Psych::VERSION >= '4.0.0' # RUBY_VERSION >= '3.1.0' YAML.unsafe_load_file('config/default.yml') else YAML.load_file('config/default.yml') end File.write( 'config/default.yml', RuboCop::RSpec::ConfigFormatter.new(current_config, descriptions).dump ) end desc 'Confirm config/default.yml is up to date' task confirm_config: :build_config do _, stdout, _, process = Open3.popen3('git diff --exit-code config/default.yml') raise <<~ERROR unless process.value.success? default.yml is out of sync: #{stdout.read} Please run `rake build_config` ERROR end desc 'Confirm documentation is up to date' task confirm_documentation: :generate_cops_documentation do stdout, _stderr, status = Open3.capture3('git diff --exit-code docs/') unless status.success? warn 'Documentation is out of sync:' warn stdout warn 'Please run `rake generate_cops_documentation` ' \ 'and add docs/ to the commit.' exit 1 end end task default: %i[build_config spec internal_investigation confirm_config documentation_syntax_check confirm_documentation] desc 'Generate a new cop template' task :new_cop, [:cop] do |_task, args| require 'rubocop' require_relative 'lib/rubocop/rspec/cop/generator' cop_name = args.fetch(:cop) do warn "usage: bundle exec rake 'new_cop[Department/Name]'" exit! end generator = RuboCop::RSpec::Cop::Generator.new(cop_name) generator.write_source generator.write_spec generator.inject_require(root_file_path: 'lib/rubocop/cop/rspec_cops.rb') generator.inject_config puts generator.todo end rubocop-rubocop-rspec-a5aeb29/config/000077500000000000000000000000001512756157400177205ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/config/default.yml000066400000000000000000001017611512756157400220750ustar00rootroot00000000000000--- RSpec: Enabled: true StyleGuideBaseURL: https://rspec.rubystyle.guide DocumentationBaseURL: https://docs.rubocop.org/rubocop-rspec Include: - "**/*_spec.rb" - "**/spec/**/*" Exclude: - "**/spec/factories.rb" - "**/spec/factories/**/*.rb" - "**/features/support/factories/**/*.rb" Language: inherit_mode: merge: - Expectations - Helpers - Hooks - Subjects ExampleGroups: inherit_mode: merge: - Regular - Skipped - Focused Regular: - describe - context - feature - example_group Skipped: - xdescribe - xcontext - xfeature Focused: - fdescribe - fcontext - ffeature Examples: inherit_mode: merge: - Regular - Skipped - Focused - Pending Regular: - it - specify - example - scenario - its Focused: - fit - fspecify - fexample - fscenario - focus Skipped: - xit - xspecify - xexample - xscenario - skip Pending: - pending Expectations: - are_expected - expect - expect_any_instance_of - is_expected - should - should_not - should_not_receive - should_receive Helpers: - let - let! Hooks: - prepend_before - before - append_before - around - prepend_after - after - append_after ErrorMatchers: - raise_error - raise_exception Includes: inherit_mode: merge: - Examples - Context Examples: - it_behaves_like - it_should_behave_like - include_examples Context: - include_context SharedGroups: inherit_mode: merge: - Examples - Context Examples: - shared_examples - shared_examples_for Context: - shared_context Subjects: - subject - subject! Metrics/BlockLength: inherit_mode: merge: - Exclude Exclude: - "**/*_spec.rb" - "**/spec/**/*" RSpec/AlignLeftLetBrace: Description: Checks that left braces for adjacent single line lets are aligned. Enabled: false VersionAdded: '1.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignLeftLetBrace RSpec/AlignRightLetBrace: Description: Checks that right braces for adjacent single line lets are aligned. Enabled: false VersionAdded: '1.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace RSpec/AnyInstance: Description: Check that instances are not being stubbed globally. Enabled: true VersionAdded: '1.4' StyleGuide: https://rspec.rubystyle.guide/#any_instance_of Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AnyInstance RSpec/AroundBlock: Description: Checks that around blocks actually run the test. Enabled: true VersionAdded: '1.11' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AroundBlock RSpec/Be: Description: Check for expectations where `be` is used without argument. Enabled: true VersionAdded: '1.25' StyleGuide: https://rspec.rubystyle.guide/#be-matcher Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be RSpec/BeEmpty: Description: Prefer using `be_empty` when checking for an empty array. Enabled: true AutoCorrect: contextual VersionAdded: '2.20' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEmpty RSpec/BeEq: Description: Check for expectations where `be(...)` can replace `eq(...)`. Enabled: true Safe: false VersionAdded: 2.9.0 VersionChanged: '2.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEq RSpec/BeEql: Description: Check for expectations where `be(...)` can replace `eql(...)`. Enabled: true Safe: false VersionAdded: '1.7' VersionChanged: '2.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql RSpec/BeNil: Description: Ensures a consistent style is used when matching `nil`. Enabled: true EnforcedStyle: be_nil SupportedStyles: - be - be_nil VersionAdded: 2.9.0 VersionChanged: 2.10.0 Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil RSpec/BeforeAfterAll: Description: Check that before/after(:all/:context) isn't being used. Enabled: true Exclude: - "**/spec/spec_helper.rb" - "**/spec/rails_helper.rb" - "**/spec/support/**/*.rb" VersionAdded: '1.12' VersionChanged: '2.23' StyleGuide: https://rspec.rubystyle.guide/#avoid-hooks-with-context-scope Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll RSpec/ChangeByZero: Description: Prefer negated matchers over `to change.by(0)`. Enabled: true VersionAdded: '2.11' VersionChanged: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero NegatedMatcher: ~ RSpec/ClassCheck: Description: Enforces consistent use of `be_a` or `be_kind_of`. StyleGuide: "#is-a-vs-kind-of" Enabled: true VersionAdded: '2.13' EnforcedStyle: be_a SupportedStyles: - be_a - be_kind_of Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck RSpec/ContainExactly: Description: Checks where `contain_exactly` is used. Enabled: true VersionAdded: '2.19' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContainExactly RSpec/ContextMethod: Description: "`context` should not be used for specifying methods." Enabled: true VersionAdded: '1.36' StyleGuide: https://rspec.rubystyle.guide/#example-group-naming Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextMethod RSpec/ContextWording: Description: Checks that `context` docstring starts with an allowed prefix. Enabled: true Prefixes: - when - with - without AllowedPatterns: [] VersionAdded: '1.20' VersionChanged: '2.13' StyleGuide: https://rspec.rubystyle.guide/#context-descriptions Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording RSpec/DescribeClass: Description: Check that the first argument to the top-level describe is a constant. Enabled: true Exclude: - "**/spec/features/**/*" - "**/spec/requests/**/*" - "**/spec/routing/**/*" - "**/spec/system/**/*" - "**/spec/views/**/*" IgnoredMetadata: type: - channel - controller - helper - job - mailer - model - request - routing - view - feature - system - mailbox - aruba - task VersionAdded: '1.0' VersionChanged: '2.7' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass RSpec/DescribeMethod: Description: Checks that the second argument to `describe` specifies a method. Enabled: true VersionAdded: '1.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeMethod RSpec/DescribeSymbol: Description: Avoid describing symbols. Enabled: true VersionAdded: '1.15' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeSymbol RSpec/DescribedClass: Description: Checks that tests use `described_class`. Enabled: true SkipBlocks: false EnforcedStyle: described_class SupportedStyles: - described_class - explicit OnlyStaticConstants: true SafeAutoCorrect: false VersionAdded: '1.0' VersionChanged: '2.27' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass RSpec/DescribedClassModuleWrapping: Description: Avoid opening modules and defining specs within them. Enabled: false VersionAdded: '1.37' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping RSpec/Dialect: Description: Enforces custom RSpec dialects. Enabled: false PreferredMethods: {} VersionAdded: '1.33' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Dialect RSpec/DuplicatedMetadata: Description: Avoid duplicated metadata. Enabled: true VersionAdded: '2.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DuplicatedMetadata RSpec/EmptyExampleGroup: Description: Checks if an example group does not include any tests. Enabled: true AutoCorrect: contextual SafeAutoCorrect: false VersionAdded: '1.7' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup RSpec/EmptyHook: Description: Checks for empty before and after hooks. Enabled: true AutoCorrect: contextual VersionAdded: '1.39' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyHook RSpec/EmptyLineAfterExample: Description: Checks if there is an empty line after example blocks. Enabled: true AllowConsecutiveOneLiners: true VersionAdded: '1.36' StyleGuide: https://rspec.rubystyle.guide/#empty-lines-around-examples Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExample RSpec/EmptyLineAfterExampleGroup: Description: Checks if there is an empty line after example group blocks. Enabled: true VersionAdded: '1.27' StyleGuide: https://rspec.rubystyle.guide/#empty-lines-between-describes Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup RSpec/EmptyLineAfterFinalLet: Description: Checks if there is an empty line after the last let block. Enabled: true VersionAdded: '1.14' StyleGuide: https://rspec.rubystyle.guide/#empty-line-after-let Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet RSpec/EmptyLineAfterHook: Description: Checks if there is an empty line after hook blocks. Enabled: true VersionAdded: '1.27' VersionChanged: '2.13' StyleGuide: https://rspec.rubystyle.guide/#empty-line-after-let Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook AllowConsecutiveOneLiners: true RSpec/EmptyLineAfterSubject: Description: Checks if there is an empty line after subject block. Enabled: true VersionAdded: '1.14' StyleGuide: https://rspec.rubystyle.guide/#empty-line-after-let Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterSubject RSpec/EmptyMetadata: Description: Avoid empty metadata hash. Enabled: true AutoCorrect: contextual VersionAdded: '2.24' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyMetadata RSpec/EmptyOutput: Description: Check that the `output` matcher is not called with an empty string. Enabled: true VersionAdded: '2.29' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyOutput RSpec/Eq: Description: Use `eq` instead of `be ==` to compare objects. Enabled: true VersionAdded: '2.24' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Eq RSpec/ExampleLength: Description: Checks for long examples. Enabled: true Max: 5 CountAsOne: [] VersionAdded: '1.5' VersionChanged: '2.3' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength RSpec/ExampleWithoutDescription: Description: Checks for examples without a description. Enabled: true EnforcedStyle: always_allow SupportedStyles: - always_allow - single_line_only - disallow VersionAdded: '1.22' StyleGuide: https://rspec.rubystyle.guide/#it-and-specify Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription RSpec/ExampleWording: Description: Checks for common mistakes in example descriptions. Enabled: true CustomTransform: be: is BE: IS have: has HAVE: HAS IgnoredWords: [] DisallowedExamples: - works VersionAdded: '1.0' VersionChanged: '2.13' StyleGuide: https://rspec.rubystyle.guide/#should-in-example-docstrings Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording RSpec/ExcessiveDocstringSpacing: Description: Checks for excessive whitespace in example descriptions. Enabled: true VersionAdded: '2.5' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExcessiveDocstringSpacing RSpec/ExpectActual: Description: Checks for `expect(...)` calls containing literal values. Enabled: true Exclude: - "**/spec/routing/**/*" VersionAdded: '1.7' VersionChanged: '2.23' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual RSpec/ExpectChange: Description: Checks for consistent style of change matcher. Enabled: true EnforcedStyle: method_call SupportedStyles: - method_call - block SafeAutoCorrect: false VersionAdded: '1.22' VersionChanged: '2.5' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange RSpec/ExpectInHook: Description: Do not use `expect` in hooks such as `before`. Enabled: true VersionAdded: '1.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook RSpec/ExpectInLet: Description: Do not use `expect` in let. Enabled: true VersionAdded: '2.30' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInLet RSpec/ExpectOutput: Description: Checks for opportunities to use `expect { ... }.to output`. Enabled: true VersionAdded: '1.10' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectOutput RSpec/Focus: Description: Checks if examples are focused. Enabled: true AutoCorrect: contextual VersionAdded: '1.5' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Focus RSpec/HookArgument: Description: Checks the arguments passed to `before`, `around`, and `after`. Enabled: true EnforcedStyle: implicit SupportedStyles: - implicit - each - example VersionAdded: '1.7' StyleGuide: https://rspec.rubystyle.guide/#redundant-beforeeach Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument RSpec/HooksBeforeExamples: Description: Checks for before/around/after hooks that come after an example. Enabled: true AutoCorrect: contextual VersionAdded: '1.29' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples RSpec/IdenticalEqualityAssertion: Description: Checks for equality assertions with identical expressions on both sides. Enabled: true VersionAdded: '2.4' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion RSpec/ImplicitBlockExpectation: Description: Check that implicit block expectation syntax is not used. Enabled: true VersionAdded: '1.35' StyleGuide: https://rspec.rubystyle.guide/#implicit-block-expectations Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitBlockExpectation RSpec/ImplicitExpect: Description: Check that a consistent implicit expectation style is used. Enabled: true EnforcedStyle: is_expected SupportedStyles: - is_expected - should VersionAdded: '1.8' StyleGuide: https://rspec.rubystyle.guide/#use-expect Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect RSpec/ImplicitSubject: Description: Checks for usage of implicit subject (`is_expected` / `should`). Enabled: true EnforcedStyle: single_line_only SupportedStyles: - single_line_only - single_statement_only - disallow - require_implicit VersionAdded: '1.29' VersionChanged: '2.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject RSpec/IncludeExamples: Description: Checks for usage of `include_examples`. Enabled: pending SafeAutoCorrect: false VersionAdded: '3.6' VersionChanged: '3.7' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IncludeExamples RSpec/IndexedLet: Description: Do not set up test data using indexes (e.g., `item_1`, `item_2`). Enabled: true VersionAdded: '2.20' VersionChanged: '2.23' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IndexedLet Max: 1 AllowedIdentifiers: [] AllowedPatterns: [] RSpec/InstanceSpy: Description: Checks for `instance_double` used with `have_received`. Enabled: true VersionAdded: '1.12' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceSpy RSpec/InstanceVariable: Description: Checks for instance variable usage in specs. Enabled: true AssignmentOnly: false VersionAdded: '1.0' VersionChanged: '1.7' StyleGuide: https://rspec.rubystyle.guide/#instance-variables Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable RSpec/IsExpectedSpecify: Description: Check for `specify` with `is_expected` and one-liner expectations. Enabled: true VersionAdded: '2.27' StyleGuide: https://rspec.rubystyle.guide/#it-and-specify Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IsExpectedSpecify RSpec/ItBehavesLike: Description: Checks that only one `it_behaves_like` style is used. Enabled: true EnforcedStyle: it_behaves_like SupportedStyles: - it_behaves_like - it_should_behave_like VersionAdded: '1.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike RSpec/IteratedExpectation: Description: Check that `all` matcher is used instead of iterating over an array. Enabled: true VersionAdded: '1.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IteratedExpectation RSpec/LeadingSubject: Description: Enforce that subject is the first definition in the test. Enabled: true VersionAdded: '1.7' VersionChanged: '1.14' StyleGuide: https://rspec.rubystyle.guide/#leading-subject Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject RSpec/LeakyConstantDeclaration: Description: Checks that no class, module, or constant is declared. Enabled: true VersionAdded: '1.35' StyleGuide: https://rspec.rubystyle.guide/#declare-constants Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration RSpec/LeakyLocalVariable: Description: Checks for local variables from outer scopes used inside examples. Enabled: pending VersionAdded: '3.8' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyLocalVariable RSpec/LetBeforeExamples: Description: Checks for `let` definitions that come after an example. Enabled: true AutoCorrect: contextual VersionAdded: '1.16' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetBeforeExamples RSpec/LetSetup: Description: Checks unreferenced `let!` calls being used for test setup. Enabled: true VersionAdded: '1.7' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetSetup RSpec/MatchArray: Description: Checks where `match_array` is used. Enabled: true VersionAdded: '2.19' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MatchArray RSpec/MessageChain: Description: Check that chains of messages are not being stubbed. Enabled: true VersionAdded: '1.7' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageChain RSpec/MessageExpectation: Description: Checks for consistent message expectation style. Enabled: false EnforcedStyle: allow SupportedStyles: - allow - expect VersionAdded: '1.7' VersionChanged: '1.8' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageExpectation RSpec/MessageSpies: Description: Checks that message expectations are set using spies. Enabled: true EnforcedStyle: have_received SupportedStyles: - have_received - receive VersionAdded: '1.9' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies RSpec/MetadataStyle: Description: Use consistent metadata style. Enabled: true EnforcedStyle: symbol SupportedStyles: - hash - symbol VersionAdded: '2.24' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MetadataStyle RSpec/MissingExampleGroupArgument: Description: Checks that the first argument to an example group is not empty. Enabled: true VersionAdded: '1.28' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument RSpec/MissingExpectationTargetMethod: Description: Checks if `.to`, `not_to` or `to_not` are used. Enabled: true VersionAdded: '3.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExpectationTargetMethod RSpec/MultipleDescribes: Description: Checks for multiple top-level example groups. Enabled: true VersionAdded: '1.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes RSpec/MultipleExpectations: Description: Checks if examples contain too many `expect` calls. Enabled: true Max: 1 VersionAdded: '1.7' VersionChanged: '1.21' StyleGuide: https://rspec.rubystyle.guide/#expectation-per-example Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations RSpec/MultipleMemoizedHelpers: Description: Checks if example groups contain too many `let` and `subject` calls. Enabled: true AllowSubject: true Max: 5 VersionAdded: '1.43' StyleGuide: https://rspec.rubystyle.guide/#let-blocks Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers RSpec/MultipleSubjects: Description: Checks if an example group defines `subject` multiple times. Enabled: true VersionAdded: '1.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleSubjects RSpec/NamedSubject: Description: Checks for explicitly referenced test subjects. Enabled: true EnforcedStyle: always SupportedStyles: - always - named_only IgnoreSharedExamples: true VersionAdded: 1.5.3 VersionChanged: '2.15' StyleGuide: https://rspec.rubystyle.guide/#use-subject Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject RSpec/NestedGroups: Description: Checks for nested example groups. Enabled: true Max: 3 AllowedGroups: [] VersionAdded: '1.7' VersionChanged: '2.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups RSpec/NoExpectationExample: Description: Checks if an example contains any expectation. Enabled: true Safe: false VersionAdded: '2.13' VersionChanged: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample AllowedPatterns: - "^expect_" - "^assert_" RSpec/NotToNot: Description: Checks for consistent method usage for negating expectations. Enabled: true EnforcedStyle: not_to SupportedStyles: - not_to - to_not VersionAdded: '1.4' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NotToNot RSpec/Output: Description: Checks for the use of output calls like puts and print in specs. Enabled: pending AutoCorrect: contextual SafeAutoCorrect: false VersionAdded: '3.9' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Output RSpec/OverwritingSetup: Description: Checks if there is a let/subject that overwrites an existing one. Enabled: true VersionAdded: '1.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup RSpec/Pending: Description: Checks for any pending or skipped examples. Enabled: false VersionAdded: '1.25' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending RSpec/PendingWithoutReason: Description: Checks for pending or skipped examples without reason. Enabled: true VersionAdded: '2.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PendingWithoutReason RSpec/PredicateMatcher: Description: Prefer using predicate matcher over using predicate method directly. Enabled: true Strict: true EnforcedStyle: inflected AllowedExplicitMatchers: [] SupportedStyles: - inflected - explicit SafeAutoCorrect: false VersionAdded: '1.16' StyleGuide: https://rspec.rubystyle.guide/#predicate-matchers Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PredicateMatcher RSpec/ReceiveCounts: Description: Check for `once` and `twice` receive counts matchers usage. Enabled: true VersionAdded: '1.26' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts RSpec/ReceiveMessages: Description: Prefer `receive_messages` over multiple `receive`s on the same object. Enabled: true SafeAutoCorrect: false VersionAdded: '2.23' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveMessages RSpec/ReceiveNever: Description: Prefer `not_to receive(...)` over `receive(...).never`. Enabled: true VersionAdded: '1.28' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever RSpec/RedundantAround: Description: Remove redundant `around` hook. Enabled: true VersionAdded: '2.19' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround RSpec/RedundantPredicateMatcher: Description: Checks for redundant predicate matcher. Enabled: true VersionAdded: '2.26' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher RSpec/RemoveConst: Description: Checks that `remove_const` is not used in specs. Enabled: true VersionAdded: '2.26' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst RSpec/RepeatedDescription: Description: Check for repeated description strings in example groups. Enabled: true VersionAdded: '1.9' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedDescription RSpec/RepeatedExample: Description: Check for repeated examples within example groups. Enabled: true VersionAdded: '1.10' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExample RSpec/RepeatedExampleGroupBody: Description: Check for repeated describe and context block body. Enabled: true VersionAdded: '1.38' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupBody RSpec/RepeatedExampleGroupDescription: Description: Check for repeated example group descriptions. Enabled: true VersionAdded: '1.38' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupDescription RSpec/RepeatedIncludeExample: Description: Check for repeated include of shared examples. Enabled: true VersionAdded: '1.44' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample RSpec/RepeatedSubjectCall: Description: Checks for repeated calls to subject missing that it is memoized. Enabled: true VersionAdded: '2.27' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedSubjectCall RSpec/ReturnFromStub: Description: Checks for consistent style of stub's return setting. Enabled: true EnforcedStyle: and_return SupportedStyles: - and_return - block VersionAdded: '1.16' VersionChanged: '1.22' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReturnFromStub RSpec/ScatteredLet: Description: Checks for let scattered across the example group. Enabled: true AutoCorrect: contextual VersionAdded: '1.14' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredLet RSpec/ScatteredSetup: Description: Checks for setup scattered across multiple hooks in an example group. Enabled: true AutoCorrect: contextual VersionAdded: '1.10' VersionChanged: '2.31' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredSetup RSpec/SharedContext: Description: Checks for proper shared_context and shared_examples usage. Enabled: true VersionAdded: '1.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext RSpec/SharedExamples: Description: Checks for consistent style for shared example names. Enabled: true EnforcedStyle: string SupportedStyles: - string - symbol VersionAdded: '1.25' VersionChanged: '2.26' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples RSpec/SingleArgumentMessageChain: Description: Checks that chains of messages contain more than one element. Enabled: true VersionAdded: '1.9' VersionChanged: '1.10' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain RSpec/SkipBlockInsideExample: Description: Checks for passing a block to `skip` within examples. Enabled: true VersionAdded: '2.19' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SkipBlockInsideExample RSpec/SortMetadata: Description: Sort RSpec metadata alphabetically. Enabled: true VersionAdded: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata RSpec/SpecFilePathFormat: Description: Checks that spec file paths are consistent and well-formed. Enabled: true Include: - "**/*_spec.rb" Exclude: - "**/spec/routing/**/*" CustomTransform: RuboCop: rubocop RSpec: rspec IgnoreMethods: false IgnoreMetadata: type: routing InflectorPath: "./config/initializers/inflections.rb" SupportedInflectors: - default - active_support EnforcedInflector: default VersionAdded: '2.24' VersionChanged: '3.8' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat RSpec/SpecFilePathSuffix: Description: Checks that spec file paths suffix are consistent and well-formed. Enabled: true VersionAdded: '2.24' Include: - "**/*_spec*rb*" - "**/spec/**/*" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix RSpec/StubbedMock: Description: Checks that message expectations do not have a configured response. Enabled: true VersionAdded: '1.44' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StubbedMock RSpec/SubjectDeclaration: Description: Ensure that subject is defined using subject helper. Enabled: true VersionAdded: '2.5' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectDeclaration RSpec/SubjectStub: Description: Checks for stubbed test subjects. Enabled: true VersionAdded: '1.7' VersionChanged: '2.8' StyleGuide: https://rspec.rubystyle.guide/#dont-stub-subject Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectStub RSpec/UndescriptiveLiteralsDescription: Description: Description should be descriptive. Enabled: true VersionAdded: '2.29' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UndescriptiveLiteralsDescription RSpec/UnspecifiedException: Description: Checks for a specified error in checking raised errors. Enabled: true VersionAdded: '1.30' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UnspecifiedException RSpec/VariableDefinition: Description: Checks that memoized helpers names are symbols or strings. Enabled: true EnforcedStyle: symbols SupportedStyles: - symbols - strings VersionAdded: '1.40' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableDefinition RSpec/VariableName: Description: Checks that memoized helper names use the configured style. Enabled: true EnforcedStyle: snake_case SupportedStyles: - snake_case - camelCase AllowedPatterns: [] VersionAdded: '1.40' VersionChanged: '2.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName RSpec/VerifiedDoubleReference: Description: Checks for consistent verified double reference style. Enabled: true SafeAutoCorrect: false VersionAdded: 2.10.0 VersionChanged: '3.4' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference RSpec/VerifiedDoubles: Description: Prefer using verifying doubles over normal doubles. Enabled: true IgnoreNameless: true IgnoreSymbolicNames: false VersionAdded: 1.2.1 VersionChanged: '1.5' StyleGuide: https://rspec.rubystyle.guide/#doubles Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles RSpec/VoidExpect: Description: Checks void `expect()`. Enabled: true VersionAdded: '1.16' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect RSpec/Yield: Description: Checks for calling a block within a stub. Enabled: true VersionAdded: '1.32' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Yield rubocop-rubocop-rspec-a5aeb29/config/obsoletion.yml000066400000000000000000000020211512756157400226130ustar00rootroot00000000000000# # Configuration of obsolete/deprecated cops used by `ConfigObsoletion`. # # See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions # # Cop parameters that have been changed # Can be treated as a warning instead of a failure with `severity: warning` changed_parameters: - cops: - RSpec/VariableName parameters: IgnoredPatterns alternative: AllowedPatterns severity: warning - cops: RSpec/VerifiedDoubleReference parameters: EnforcedStyle reason: String references are not verifying unless the class is loaded. split: RSpec/FilePath: alternatives: - RSpec/SpecFilePathFormat - RSpec/SpecFilePathSuffix removed: RSpec/Capybara/FeatureMethods: reason: > this cop has migrated to `RSpec/Dialect`. Please use `RSpec/Dialect` instead RSpec/StringAsInstanceDoubleConstant: reason: Please use `RSpec/VerifiedDoubleReference` instead extracted: RSpec/Rails/*: rubocop-rspec_rails RSpec/FactoryBot/*: rubocop-factory_bot RSpec/Capybara/*: rubocop-capybara rubocop-rubocop-rspec-a5aeb29/docs/000077500000000000000000000000001512756157400174035ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/docs/antora.yml000066400000000000000000000001271512756157400214120ustar00rootroot00000000000000name: rubocop-rspec title: RuboCop RSpec version: '3.9' nav: - modules/ROOT/nav.adoc rubocop-rubocop-rspec-a5aeb29/docs/modules/000077500000000000000000000000001512756157400210535ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/000077500000000000000000000000001512756157400216365ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/nav.adoc000066400000000000000000000006071512756157400232550ustar00rootroot00000000000000* xref:index.adoc[Home] * xref:installation.adoc[Installation] * xref:usage.adoc[Usage] * xref:cops.adoc[Cops] * xref:upgrade_to_version_2.adoc[Upgrade to 2.x] * xref:upgrade_to_version_3.adoc[Upgrade to 3.x] * xref:third_party_rspec_syntax_extensions.adoc[RSpec syntax extensions in third-party gems] * xref:development.adoc[Development] * Cops Documentation ** xref:cops_rspec.adoc[RSpec] rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/000077500000000000000000000000001512756157400227355ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/cops.adoc000066400000000000000000000170551512756157400245410ustar00rootroot00000000000000// START_COP_LIST === Department xref:cops_rspec.adoc[RSpec] * xref:cops_rspec.adoc#rspecalignleftletbrace[RSpec/AlignLeftLetBrace] * xref:cops_rspec.adoc#rspecalignrightletbrace[RSpec/AlignRightLetBrace] * xref:cops_rspec.adoc#rspecanyinstance[RSpec/AnyInstance] * xref:cops_rspec.adoc#rspecaroundblock[RSpec/AroundBlock] * xref:cops_rspec.adoc#rspecbe[RSpec/Be] * xref:cops_rspec.adoc#rspecbeempty[RSpec/BeEmpty] * xref:cops_rspec.adoc#rspecbeeq[RSpec/BeEq] * xref:cops_rspec.adoc#rspecbeeql[RSpec/BeEql] * xref:cops_rspec.adoc#rspecbenil[RSpec/BeNil] * xref:cops_rspec.adoc#rspecbeforeafterall[RSpec/BeforeAfterAll] * xref:cops_rspec.adoc#rspecchangebyzero[RSpec/ChangeByZero] * xref:cops_rspec.adoc#rspecclasscheck[RSpec/ClassCheck] * xref:cops_rspec.adoc#rspeccontainexactly[RSpec/ContainExactly] * xref:cops_rspec.adoc#rspeccontextmethod[RSpec/ContextMethod] * xref:cops_rspec.adoc#rspeccontextwording[RSpec/ContextWording] * xref:cops_rspec.adoc#rspecdescribeclass[RSpec/DescribeClass] * xref:cops_rspec.adoc#rspecdescribemethod[RSpec/DescribeMethod] * xref:cops_rspec.adoc#rspecdescribesymbol[RSpec/DescribeSymbol] * xref:cops_rspec.adoc#rspecdescribedclass[RSpec/DescribedClass] * xref:cops_rspec.adoc#rspecdescribedclassmodulewrapping[RSpec/DescribedClassModuleWrapping] * xref:cops_rspec.adoc#rspecdialect[RSpec/Dialect] * xref:cops_rspec.adoc#rspecduplicatedmetadata[RSpec/DuplicatedMetadata] * xref:cops_rspec.adoc#rspecemptyexamplegroup[RSpec/EmptyExampleGroup] * xref:cops_rspec.adoc#rspecemptyhook[RSpec/EmptyHook] * xref:cops_rspec.adoc#rspecemptylineafterexample[RSpec/EmptyLineAfterExample] * xref:cops_rspec.adoc#rspecemptylineafterexamplegroup[RSpec/EmptyLineAfterExampleGroup] * xref:cops_rspec.adoc#rspecemptylineafterfinallet[RSpec/EmptyLineAfterFinalLet] * xref:cops_rspec.adoc#rspecemptylineafterhook[RSpec/EmptyLineAfterHook] * xref:cops_rspec.adoc#rspecemptylineaftersubject[RSpec/EmptyLineAfterSubject] * xref:cops_rspec.adoc#rspecemptymetadata[RSpec/EmptyMetadata] * xref:cops_rspec.adoc#rspecemptyoutput[RSpec/EmptyOutput] * xref:cops_rspec.adoc#rspeceq[RSpec/Eq] * xref:cops_rspec.adoc#rspecexamplelength[RSpec/ExampleLength] * xref:cops_rspec.adoc#rspecexamplewithoutdescription[RSpec/ExampleWithoutDescription] * xref:cops_rspec.adoc#rspecexamplewording[RSpec/ExampleWording] * xref:cops_rspec.adoc#rspecexcessivedocstringspacing[RSpec/ExcessiveDocstringSpacing] * xref:cops_rspec.adoc#rspecexpectactual[RSpec/ExpectActual] * xref:cops_rspec.adoc#rspecexpectchange[RSpec/ExpectChange] * xref:cops_rspec.adoc#rspecexpectinhook[RSpec/ExpectInHook] * xref:cops_rspec.adoc#rspecexpectinlet[RSpec/ExpectInLet] * xref:cops_rspec.adoc#rspecexpectoutput[RSpec/ExpectOutput] * xref:cops_rspec.adoc#rspecfocus[RSpec/Focus] * xref:cops_rspec.adoc#rspechookargument[RSpec/HookArgument] * xref:cops_rspec.adoc#rspechooksbeforeexamples[RSpec/HooksBeforeExamples] * xref:cops_rspec.adoc#rspecidenticalequalityassertion[RSpec/IdenticalEqualityAssertion] * xref:cops_rspec.adoc#rspecimplicitblockexpectation[RSpec/ImplicitBlockExpectation] * xref:cops_rspec.adoc#rspecimplicitexpect[RSpec/ImplicitExpect] * xref:cops_rspec.adoc#rspecimplicitsubject[RSpec/ImplicitSubject] * xref:cops_rspec.adoc#rspecincludeexamples[RSpec/IncludeExamples] * xref:cops_rspec.adoc#rspecindexedlet[RSpec/IndexedLet] * xref:cops_rspec.adoc#rspecinstancespy[RSpec/InstanceSpy] * xref:cops_rspec.adoc#rspecinstancevariable[RSpec/InstanceVariable] * xref:cops_rspec.adoc#rspecisexpectedspecify[RSpec/IsExpectedSpecify] * xref:cops_rspec.adoc#rspecitbehaveslike[RSpec/ItBehavesLike] * xref:cops_rspec.adoc#rspeciteratedexpectation[RSpec/IteratedExpectation] * xref:cops_rspec.adoc#rspecleadingsubject[RSpec/LeadingSubject] * xref:cops_rspec.adoc#rspecleakyconstantdeclaration[RSpec/LeakyConstantDeclaration] * xref:cops_rspec.adoc#rspecleakylocalvariable[RSpec/LeakyLocalVariable] * xref:cops_rspec.adoc#rspecletbeforeexamples[RSpec/LetBeforeExamples] * xref:cops_rspec.adoc#rspecletsetup[RSpec/LetSetup] * xref:cops_rspec.adoc#rspecmatcharray[RSpec/MatchArray] * xref:cops_rspec.adoc#rspecmessagechain[RSpec/MessageChain] * xref:cops_rspec.adoc#rspecmessageexpectation[RSpec/MessageExpectation] * xref:cops_rspec.adoc#rspecmessagespies[RSpec/MessageSpies] * xref:cops_rspec.adoc#rspecmetadatastyle[RSpec/MetadataStyle] * xref:cops_rspec.adoc#rspecmissingexamplegroupargument[RSpec/MissingExampleGroupArgument] * xref:cops_rspec.adoc#rspecmissingexpectationtargetmethod[RSpec/MissingExpectationTargetMethod] * xref:cops_rspec.adoc#rspecmultipledescribes[RSpec/MultipleDescribes] * xref:cops_rspec.adoc#rspecmultipleexpectations[RSpec/MultipleExpectations] * xref:cops_rspec.adoc#rspecmultiplememoizedhelpers[RSpec/MultipleMemoizedHelpers] * xref:cops_rspec.adoc#rspecmultiplesubjects[RSpec/MultipleSubjects] * xref:cops_rspec.adoc#rspecnamedsubject[RSpec/NamedSubject] * xref:cops_rspec.adoc#rspecnestedgroups[RSpec/NestedGroups] * xref:cops_rspec.adoc#rspecnoexpectationexample[RSpec/NoExpectationExample] * xref:cops_rspec.adoc#rspecnottonot[RSpec/NotToNot] * xref:cops_rspec.adoc#rspecoutput[RSpec/Output] * xref:cops_rspec.adoc#rspecoverwritingsetup[RSpec/OverwritingSetup] * xref:cops_rspec.adoc#rspecpending[RSpec/Pending] * xref:cops_rspec.adoc#rspecpendingwithoutreason[RSpec/PendingWithoutReason] * xref:cops_rspec.adoc#rspecpredicatematcher[RSpec/PredicateMatcher] * xref:cops_rspec.adoc#rspecreceivecounts[RSpec/ReceiveCounts] * xref:cops_rspec.adoc#rspecreceivemessages[RSpec/ReceiveMessages] * xref:cops_rspec.adoc#rspecreceivenever[RSpec/ReceiveNever] * xref:cops_rspec.adoc#rspecredundantaround[RSpec/RedundantAround] * xref:cops_rspec.adoc#rspecredundantpredicatematcher[RSpec/RedundantPredicateMatcher] * xref:cops_rspec.adoc#rspecremoveconst[RSpec/RemoveConst] * xref:cops_rspec.adoc#rspecrepeateddescription[RSpec/RepeatedDescription] * xref:cops_rspec.adoc#rspecrepeatedexample[RSpec/RepeatedExample] * xref:cops_rspec.adoc#rspecrepeatedexamplegroupbody[RSpec/RepeatedExampleGroupBody] * xref:cops_rspec.adoc#rspecrepeatedexamplegroupdescription[RSpec/RepeatedExampleGroupDescription] * xref:cops_rspec.adoc#rspecrepeatedincludeexample[RSpec/RepeatedIncludeExample] * xref:cops_rspec.adoc#rspecrepeatedsubjectcall[RSpec/RepeatedSubjectCall] * xref:cops_rspec.adoc#rspecreturnfromstub[RSpec/ReturnFromStub] * xref:cops_rspec.adoc#rspecscatteredlet[RSpec/ScatteredLet] * xref:cops_rspec.adoc#rspecscatteredsetup[RSpec/ScatteredSetup] * xref:cops_rspec.adoc#rspecsharedcontext[RSpec/SharedContext] * xref:cops_rspec.adoc#rspecsharedexamples[RSpec/SharedExamples] * xref:cops_rspec.adoc#rspecsingleargumentmessagechain[RSpec/SingleArgumentMessageChain] * xref:cops_rspec.adoc#rspecskipblockinsideexample[RSpec/SkipBlockInsideExample] * xref:cops_rspec.adoc#rspecsortmetadata[RSpec/SortMetadata] * xref:cops_rspec.adoc#rspecspecfilepathformat[RSpec/SpecFilePathFormat] * xref:cops_rspec.adoc#rspecspecfilepathsuffix[RSpec/SpecFilePathSuffix] * xref:cops_rspec.adoc#rspecstubbedmock[RSpec/StubbedMock] * xref:cops_rspec.adoc#rspecsubjectdeclaration[RSpec/SubjectDeclaration] * xref:cops_rspec.adoc#rspecsubjectstub[RSpec/SubjectStub] * xref:cops_rspec.adoc#rspecundescriptiveliteralsdescription[RSpec/UndescriptiveLiteralsDescription] * xref:cops_rspec.adoc#rspecunspecifiedexception[RSpec/UnspecifiedException] * xref:cops_rspec.adoc#rspecvariabledefinition[RSpec/VariableDefinition] * xref:cops_rspec.adoc#rspecvariablename[RSpec/VariableName] * xref:cops_rspec.adoc#rspecverifieddoublereference[RSpec/VerifiedDoubleReference] * xref:cops_rspec.adoc#rspecverifieddoubles[RSpec/VerifiedDoubles] * xref:cops_rspec.adoc#rspecvoidexpect[RSpec/VoidExpect] * xref:cops_rspec.adoc#rspecyield[RSpec/Yield] // END_COP_LIST rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/cops_rspec.adoc000066400000000000000000003620601512756157400257340ustar00rootroot00000000000000//// Do NOT edit this file by hand directly, as it is automatically generated. Please make any necessary changes to the cop documentation within the source files themselves. //// = RSpec [#rspecalignleftletbrace] == RSpec/AlignLeftLetBrace |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | Always | 1.16 | - |=== Checks that left braces for adjacent single line lets are aligned. [#examples-rspecalignleftletbrace] === Examples [source,ruby] ---- # bad let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } # good let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } ---- [#references-rspecalignleftletbrace] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignLeftLetBrace [#rspecalignrightletbrace] == RSpec/AlignRightLetBrace |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | Always | 1.16 | - |=== Checks that right braces for adjacent single line lets are aligned. [#examples-rspecalignrightletbrace] === Examples [source,ruby] ---- # bad let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } # good let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } ---- [#references-rspecalignrightletbrace] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace [#rspecanyinstance] == RSpec/AnyInstance |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.4 | - |=== Check that instances are not being stubbed globally. Prefer instance doubles over stubbing any instance of a class [#examples-rspecanyinstance] === Examples [source,ruby] ---- # bad describe MyClass do before { allow_any_instance_of(MyClass).to receive(:foo) } end # good describe MyClass do let(:my_instance) { instance_double(MyClass) } before do allow(MyClass).to receive(:new).and_return(my_instance) allow(my_instance).to receive(:foo) end end ---- [#references-rspecanyinstance] === References * https://rspec.rubystyle.guide/#any_instance_of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AnyInstance [#rspecaroundblock] == RSpec/AroundBlock |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.11 | - |=== Checks that around blocks actually run the test. [#examples-rspecaroundblock] === Examples [source,ruby] ---- # bad around do some_method end around do |test| some_method end # good around do |test| some_method test.call end around do |test| some_method test.run end ---- [#references-rspecaroundblock] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AroundBlock [#rspecbe] == RSpec/Be |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.25 | - |=== Check for expectations where `be` is used without argument. The `be` matcher is too generic, as it pass on everything that is not nil or false. If that is the exact intend, use `be_truthy`. In all other cases it's better to specify what exactly is the expected value. [#examples-rspecbe] === Examples [source,ruby] ---- # bad expect(foo).to be # good expect(foo).to be_truthy expect(foo).to be 1.0 expect(foo).to be(true) ---- [#references-rspecbe] === References * https://rspec.rubystyle.guide/#be-matcher * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be [#rspecbeempty] == RSpec/BeEmpty |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 2.20 | 2.31 |=== Prefer using `be_empty` when checking for an empty array. [#examples-rspecbeempty] === Examples [source,ruby] ---- # bad expect(array).to contain_exactly expect(array).to match_array([]) # good expect(array).to be_empty ---- [#references-rspecbeempty] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEmpty [#rspecbeeq] == RSpec/BeEq |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | No | Always (Unsafe) | 2.9.0 | 2.16 |=== Check for expectations where `be(...)` can replace `eq(...)`. The `be` matcher compares by identity while the `eq` matcher compares using `==`. Booleans and nil can be compared by identity and therefore the `be` matcher is preferable as it is a more strict test. [#safety-rspecbeeq] === Safety This cop is unsafe because it changes how values are compared. [#examples-rspecbeeq] === Examples [source,ruby] ---- # bad expect(foo).to eq(true) expect(foo).to eq(false) expect(foo).to eq(nil) # good expect(foo).to be(true) expect(foo).to be(false) expect(foo).to be(nil) ---- [#references-rspecbeeq] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEq [#rspecbeeql] == RSpec/BeEql |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | No | Always (Unsafe) | 1.7 | 2.16 |=== Check for expectations where `be(...)` can replace `eql(...)`. The `be` matcher compares by identity while the `eql` matcher compares using `eql?`. Integers, floats, booleans, symbols, and nil can be compared by identity and therefore the `be` matcher is preferable as it is a more strict test. This cop only looks for instances of `expect(...).to eql(...)`. We do not check `to_not` or `not_to` since `!eql?` is more strict than `!equal?`. We also do not try to flag `eq` because if `a == b`, and `b` is comparable by identity, `a` is still not necessarily the same type as `b` since the `#==` operator can coerce objects for comparison. [#safety-rspecbeeql] === Safety This cop is unsafe because it changes how values are compared. [#examples-rspecbeeql] === Examples [source,ruby] ---- # bad expect(foo).to eql(1) expect(foo).to eql(1.0) expect(foo).to eql(true) expect(foo).to eql(false) expect(foo).to eql(:bar) expect(foo).to eql(nil) # good expect(foo).to be(1) expect(foo).to be(1.0) expect(foo).to be(true) expect(foo).to be(false) expect(foo).to be(:bar) expect(foo).to be(nil) ---- [#references-rspecbeeql] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql [#rspecbenil] == RSpec/BeNil |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.9.0 | 2.10.0 |=== Ensures a consistent style is used when matching `nil`. You can either use the more specific `be_nil` matcher, or the more generic `be` matcher with a `nil` argument. This cop can be configured using the `EnforcedStyle` option [#examples-rspecbenil] === Examples [#_enforcedstyle_-be_nil_-_default_-rspecbenil] ==== `EnforcedStyle: be_nil` (default) [source,ruby] ---- # bad expect(foo).to be(nil) # good expect(foo).to be_nil ---- [#_enforcedstyle_-be_-rspecbenil] ==== `EnforcedStyle: be` [source,ruby] ---- # bad expect(foo).to be_nil # good expect(foo).to be(nil) ---- [#configurable-attributes-rspecbenil] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `be_nil` | `be`, `be_nil` |=== [#references-rspecbenil] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil [#rspecbeforeafterall] == RSpec/BeforeAfterAll |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.12 | 2.23 |=== Check that before/after(:all/:context) isn't being used. [#examples-rspecbeforeafterall] === Examples [source,ruby] ---- # bad - Faster but risk of state leaking between examples describe MyClass do before(:all) { Widget.create } after(:context) { Widget.delete_all } end # good - Slower but examples are properly isolated describe MyClass do before(:each) { Widget.create } after(:each) { Widget.delete_all } end ---- [#configurable-attributes-rspecbeforeafterall] === Configurable attributes |=== | Name | Default value | Configurable values | Exclude | `+**/spec/spec_helper.rb+`, `+**/spec/rails_helper.rb+`, `+**/spec/support/**/*.rb+` | Array |=== [#references-rspecbeforeafterall] === References * https://rspec.rubystyle.guide/#avoid-hooks-with-context-scope * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll [#rspecchangebyzero] == RSpec/ChangeByZero |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.11 | 2.14 |=== Prefer negated matchers over `to change.by(0)`. In the case of composite expectations, cop suggest using the negation matchers of `RSpec::Matchers#change`. By default the cop does not support autocorrect of compound expectations, but if you set the negated matcher for `change`, e.g. `not_change` with the `NegatedMatcher` option, the cop will perform the autocorrection. [#examples-rspecchangebyzero] === Examples [#negatedmatcher_-_-_default_-rspecchangebyzero] ==== NegatedMatcher: ~ (default) [source,ruby] ---- # bad expect { run }.to change(Foo, :bar).by(0) expect { run }.to change { Foo.bar }.by(0) # bad - compound expectations (does not support autocorrection) expect { run } .to change(Foo, :bar).by(0) .and change(Foo, :baz).by(0) expect { run } .to change { Foo.bar }.by(0) .and change { Foo.baz }.by(0) # good expect { run }.not_to change(Foo, :bar) expect { run }.not_to change { Foo.bar } # good - compound expectations define_negated_matcher :not_change, :change expect { run } .to not_change(Foo, :bar) .and not_change(Foo, :baz) expect { run } .to not_change { Foo.bar } .and not_change { Foo.baz } ---- [#negatedmatcher_-not_change-rspecchangebyzero] ==== NegatedMatcher: not_change [source,ruby] ---- # bad (support autocorrection to good case) expect { run } .to change(Foo, :bar).by(0) .and change(Foo, :baz).by(0) expect { run } .to change { Foo.bar }.by(0) .and change { Foo.baz }.by(0) # good define_negated_matcher :not_change, :change expect { run } .to not_change(Foo, :bar) .and not_change(Foo, :baz) expect { run } .to not_change { Foo.bar } .and not_change { Foo.baz } ---- [#configurable-attributes-rspecchangebyzero] === Configurable attributes |=== | Name | Default value | Configurable values | NegatedMatcher | `` | |=== [#references-rspecchangebyzero] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero [#rspecclasscheck] == RSpec/ClassCheck |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.13 | - |=== Enforces consistent use of `be_a` or `be_kind_of`. [#examples-rspecclasscheck] === Examples [#enforcedstyle_-be_a-_default_-rspecclasscheck] ==== EnforcedStyle: be_a (default) [source,ruby] ---- # bad expect(object).to be_kind_of(String) expect(object).to be_a_kind_of(String) # good expect(object).to be_a(String) expect(object).to be_an(String) ---- [#enforcedstyle_-be_kind_of-rspecclasscheck] ==== EnforcedStyle: be_kind_of [source,ruby] ---- # bad expect(object).to be_a(String) expect(object).to be_an(String) # good expect(object).to be_kind_of(String) expect(object).to be_a_kind_of(String) ---- [#configurable-attributes-rspecclasscheck] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `be_a` | `be_a`, `be_kind_of` |=== [#references-rspecclasscheck] === References * https://rubystyle.guide#is-a-vs-kind-of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck [#rspeccontainexactly] == RSpec/ContainExactly |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.19 | - |=== Checks where `contain_exactly` is used. This cop checks for the following: - Prefer `match_array` when matching array values. - Prefer `be_empty` when using `contain_exactly` with no arguments. [#examples-rspeccontainexactly] === Examples [source,ruby] ---- # bad it { is_expected.to contain_exactly(*array1, *array2) } # good it { is_expected.to match_array(array1 + array2) } # good it { is_expected.to contain_exactly(content, *array) } ---- [#references-rspeccontainexactly] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContainExactly [#rspeccontextmethod] == RSpec/ContextMethod |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.36 | - |=== `context` should not be used for specifying methods. [#examples-rspeccontextmethod] === Examples [source,ruby] ---- # bad context '#foo_bar' do # ... end context '.foo_bar' do # ... end # good describe '#foo_bar' do # ... end describe '.foo_bar' do # ... end ---- [#references-rspeccontextmethod] === References * https://rspec.rubystyle.guide/#example-group-naming * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextMethod [#rspeccontextwording] == RSpec/ContextWording |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.20 | 2.13 |=== Checks that `context` docstring starts with an allowed prefix. The default list of prefixes is minimal. Users are encouraged to tailor the configuration to meet project needs. Other acceptable prefixes may include `if`, `unless`, `for`, `before`, `after`, or `during`. They may consist of multiple words if desired. If both `Prefixes` and `AllowedPatterns` are empty, this cop will always report an offense. So you need to set at least one of them. This cop can be customized allowed context description pattern with `AllowedPatterns`. By default, there are no checking by pattern. [#examples-rspeccontextwording] === Examples [#_prefixes_-configuration-rspeccontextwording] ==== `Prefixes` configuration [source,ruby] ---- # .rubocop.yml # RSpec/ContextWording: # Prefixes: # - when # - with # - without # - if # - unless # - for ---- [source,ruby] ---- # bad context 'the display name not present' do # ... end # good context 'when the display name is not present' do # ... end ---- [#_allowedpatterns_-configuration-rspeccontextwording] ==== `AllowedPatterns` configuration [source,ruby] ---- # .rubocop.yml # RSpec/ContextWording: # AllowedPatterns: # - とき$ ---- [source,ruby] ---- # bad context '条件を満たす' do # ... end # good context '条件を満たすとき' do # ... end ---- [#configurable-attributes-rspeccontextwording] === Configurable attributes |=== | Name | Default value | Configurable values | Prefixes | `when`, `with`, `without` | Array | AllowedPatterns | `[]` | Array |=== [#references-rspeccontextwording] === References * https://rspec.rubystyle.guide/#context-descriptions * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording * http://www.betterspecs.org/#contexts [#rspecdescribeclass] == RSpec/DescribeClass |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.0 | 2.7 |=== Check that the first argument to the top-level describe is a constant. It can be configured to ignore strings when certain metadata is passed. Ignores Rails and Aruba `type` metadata by default. [#examples-rspecdescribeclass] === Examples [#_ignoredmetadata_-configuration-rspecdescribeclass] ==== `IgnoredMetadata` configuration [source,ruby] ---- # .rubocop.yml # RSpec/DescribeClass: # IgnoredMetadata: # type: # - request # - controller ---- [source,ruby] ---- # bad describe 'Do something' do end # good describe TestedClass do subject { described_class } end describe 'TestedClass::VERSION' do subject { Object.const_get(self.class.description) } end describe "A feature example", type: :feature do end ---- [#configurable-attributes-rspecdescribeclass] === Configurable attributes |=== | Name | Default value | Configurable values | Exclude | `+**/spec/features/**/*+`, `+**/spec/requests/**/*+`, `+**/spec/routing/**/*+`, `+**/spec/system/**/*+`, `+**/spec/views/**/*+` | Array | IgnoredMetadata | `{"type" => ["channel", "controller", "helper", "job", "mailer", "model", "request", "routing", "view", "feature", "system", "mailbox", "aruba", "task"]}` | |=== [#references-rspecdescribeclass] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass [#rspecdescribemethod] == RSpec/DescribeMethod |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.0 | - |=== Checks that the second argument to `describe` specifies a method. [#examples-rspecdescribemethod] === Examples [source,ruby] ---- # bad describe MyClass, 'do something' do end # good describe MyClass, '#my_instance_method' do end describe MyClass, '.my_class_method' do end ---- [#references-rspecdescribemethod] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeMethod [#rspecdescribesymbol] == RSpec/DescribeSymbol |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.15 | - |=== Avoid describing symbols. [#examples-rspecdescribesymbol] === Examples [source,ruby] ---- # bad describe :my_method do # ... end # good describe '#my_method' do # ... end ---- [#references-rspecdescribesymbol] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeSymbol * https://github.com/rspec/rspec-core/issues/1610 [#rspecdescribedclass] == RSpec/DescribedClass |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always (Unsafe) | 1.0 | 2.27 |=== Checks that tests use `described_class`. If the first argument of describe is a class, the class is exposed to each example via described_class. This cop can be configured using the `EnforcedStyle`, `SkipBlocks` and `OnlyStaticConstants` options. `OnlyStaticConstants` is only relevant when `EnforcedStyle` is `described_class`. There's a known caveat with rspec-rails's `controller` helper that runs its block in a different context, and `described_class` is not available to it. `SkipBlocks` option excludes detection in all non-RSpec related blocks. To narrow down this setting to only a specific directory, it is possible to use an overriding configuration file local to that directory. [#safety-rspecdescribedclass] === Safety Autocorrection is unsafe when `SkipBlocks: false` because `described_class` might not be available within the block (for example, in rspec-rails's `controller` helper). [#examples-rspecdescribedclass] === Examples [#_enforcedstyle_-described_class_-_default_-rspecdescribedclass] ==== `EnforcedStyle: described_class` (default) [source,ruby] ---- # bad describe MyClass do subject { MyClass.do_something } end # good describe MyClass do subject { described_class.do_something } end ---- [#_onlystaticconstants_-true_-_default_-rspecdescribedclass] ==== `OnlyStaticConstants: true` (default) [source,ruby] ---- # good describe MyClass do subject { MyClass::CONSTANT } end ---- [#_onlystaticconstants_-false_-rspecdescribedclass] ==== `OnlyStaticConstants: false` [source,ruby] ---- # bad describe MyClass do subject { MyClass::CONSTANT } end ---- [#_enforcedstyle_-explicit_-rspecdescribedclass] ==== `EnforcedStyle: explicit` [source,ruby] ---- # bad describe MyClass do subject { described_class.do_something } end # good describe MyClass do subject { MyClass.do_something } end ---- [#_skipblocks_-true_-rspecdescribedclass] ==== `SkipBlocks: true` [source,ruby] ---- # spec/controllers/.rubocop.yml # RSpec/DescribedClass: # SkipBlocks: true # acceptable describe MyConcern do controller(ApplicationController) do include MyConcern end end ---- [#configurable-attributes-rspecdescribedclass] === Configurable attributes |=== | Name | Default value | Configurable values | SkipBlocks | `false` | Boolean | EnforcedStyle | `described_class` | `described_class`, `explicit` | OnlyStaticConstants | `true` | Boolean |=== [#references-rspecdescribedclass] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass [#rspecdescribedclassmodulewrapping] == RSpec/DescribedClassModuleWrapping |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | No | 1.37 | - |=== Avoid opening modules and defining specs within them. [#examples-rspecdescribedclassmodulewrapping] === Examples [source,ruby] ---- # bad module MyModule RSpec.describe MyClass do # ... end end # good RSpec.describe MyModule::MyClass do # ... end ---- [#references-rspecdescribedclassmodulewrapping] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping * https://github.com/rubocop/rubocop-rspec/issues/735 [#rspecdialect] == RSpec/Dialect |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | Always | 1.33 | - |=== Enforces custom RSpec dialects. A dialect can be based on the following RSpec methods: - describe, context, feature, example_group - xdescribe, xcontext, xfeature - fdescribe, fcontext, ffeature - shared_examples, shared_examples_for, shared_context - it, specify, example, scenario, its - fit, fspecify, fexample, fscenario, focus - xit, xspecify, xexample, xscenario, skip - pending - prepend_before, before, append_before, - around - prepend_after, after, append_after - let, let! - subject, subject! - expect, is_expected, expect_any_instance_of - raise_error, raise_exception By default all of the RSpec methods and aliases are allowed. By setting a config like: RSpec/Dialect: PreferredMethods: context: describe If you were previously using the `RSpec/Capybara/FeatureMethods` cop and want to keep disabling all Capybara-specific methods that have the same native RSpec method (e.g. are just aliases), use the following config: RSpec/Dialect: PreferredMethods: background: :before scenario: :it xscenario: :xit given: :let given!: :let! feature: :describe You can expect the following behavior: [#examples-rspecdialect] === Examples [source,ruby] ---- # bad context 'display name presence' do # ... end # good describe 'display name presence' do # ... end ---- [#configurable-attributes-rspecdialect] === Configurable attributes |=== | Name | Default value | Configurable values | PreferredMethods | `{}` | |=== [#references-rspecdialect] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Dialect [#rspecduplicatedmetadata] == RSpec/DuplicatedMetadata |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.16 | - |=== Avoid duplicated metadata. [#examples-rspecduplicatedmetadata] === Examples [source,ruby] ---- # bad describe 'Something', :a, :a # good describe 'Something', :a ---- [#references-rspecduplicatedmetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DuplicatedMetadata [#rspecemptyexamplegroup] == RSpec/EmptyExampleGroup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only (Unsafe) | 1.7 | 2.31 |=== Checks if an example group does not include any tests. [#examples-rspecemptyexamplegroup] === Examples [#usage-rspecemptyexamplegroup] ==== usage [source,ruby] ---- # bad describe Bacon do let(:bacon) { Bacon.new(chunkiness) } let(:chunkiness) { false } context 'extra chunky' do # flagged by rubocop let(:chunkiness) { true } end it 'is chunky' do expect(bacon.chunky?).to be_truthy end end # good describe Bacon do let(:bacon) { Bacon.new(chunkiness) } let(:chunkiness) { false } it 'is chunky' do expect(bacon.chunky?).to be_truthy end end # good describe Bacon do pending 'will add tests later' end ---- [#references-rspecemptyexamplegroup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup [#rspecemptyhook] == RSpec/EmptyHook |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 1.39 | 2.31 |=== Checks for empty before and after hooks. [#examples-rspecemptyhook] === Examples [source,ruby] ---- # bad before {} after do; end before(:all) do end after(:all) { } # good before { create_users } after do cleanup_users end before(:all) do create_feed end after(:all) { cleanup_feed } ---- [#references-rspecemptyhook] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyHook [#rspecemptylineafterexample] == RSpec/EmptyLineAfterExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.36 | - |=== Checks if there is an empty line after example blocks. [#examples-rspecemptylineafterexample] === Examples [source,ruby] ---- # bad RSpec.describe Foo do it 'does this' do end it 'does that' do end end # good RSpec.describe Foo do it 'does this' do end it 'does that' do end end # fair - it's ok to have non-separated one-liners RSpec.describe Foo do it { one } it { two } end ---- [#with-allowconsecutiveoneliners-configuration-rspecemptylineafterexample] ==== with AllowConsecutiveOneLiners configuration [source,ruby] ---- # rubocop.yml # RSpec/EmptyLineAfterExample: # AllowConsecutiveOneLiners: false # bad RSpec.describe Foo do it { one } it { two } end ---- [#configurable-attributes-rspecemptylineafterexample] === Configurable attributes |=== | Name | Default value | Configurable values | AllowConsecutiveOneLiners | `true` | Boolean |=== [#references-rspecemptylineafterexample] === References * https://rspec.rubystyle.guide/#empty-lines-around-examples * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExample [#rspecemptylineafterexamplegroup] == RSpec/EmptyLineAfterExampleGroup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.27 | - |=== Checks if there is an empty line after example group blocks. [#examples-rspecemptylineafterexamplegroup] === Examples [source,ruby] ---- # bad RSpec.describe Foo do describe '#bar' do end describe '#baz' do end end # good RSpec.describe Foo do describe '#bar' do end describe '#baz' do end end ---- [#references-rspecemptylineafterexamplegroup] === References * https://rspec.rubystyle.guide/#empty-lines-between-describes * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup [#rspecemptylineafterfinallet] == RSpec/EmptyLineAfterFinalLet |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.14 | - |=== Checks if there is an empty line after the last let block. [#examples-rspecemptylineafterfinallet] === Examples [source,ruby] ---- # bad let(:foo) { bar } let(:something) { other } it { does_something } # good let(:foo) { bar } let(:something) { other } it { does_something } ---- [#references-rspecemptylineafterfinallet] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet [#rspecemptylineafterhook] == RSpec/EmptyLineAfterHook |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.27 | 2.13 |=== Checks if there is an empty line after hook blocks. `AllowConsecutiveOneLiners` configures whether adjacent one-line definitions are considered an offense. [#examples-rspecemptylineafterhook] === Examples [source,ruby] ---- # bad before { do_something } it { does_something } # bad after { do_something } it { does_something } # bad around { |test| test.run } it { does_something } # good after { do_something } it { does_something } # fair - it's ok to have non-separated one-liners hooks around { |test| test.run } after { do_something } it { does_something } ---- [#with-allowconsecutiveoneliners-configuration-rspecemptylineafterhook] ==== with AllowConsecutiveOneLiners configuration [source,ruby] ---- # rubocop.yml # RSpec/EmptyLineAfterHook: # AllowConsecutiveOneLiners: false # bad around { |test| test.run } after { do_something } it { does_something } # good around { |test| test.run } after { do_something } it { does_something } ---- [#configurable-attributes-rspecemptylineafterhook] === Configurable attributes |=== | Name | Default value | Configurable values | AllowConsecutiveOneLiners | `true` | Boolean |=== [#references-rspecemptylineafterhook] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook [#rspecemptylineaftersubject] == RSpec/EmptyLineAfterSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.14 | - |=== Checks if there is an empty line after subject block. [#examples-rspecemptylineaftersubject] === Examples [source,ruby] ---- # bad subject(:obj) { described_class } let(:foo) { bar } # good subject(:obj) { described_class } let(:foo) { bar } ---- [#references-rspecemptylineaftersubject] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterSubject [#rspecemptymetadata] == RSpec/EmptyMetadata |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 2.24 | 2.31 |=== Avoid empty metadata hash. [#examples-rspecemptymetadata] === Examples [#enforcedstyle_-symbol-_default_-rspecemptymetadata] ==== EnforcedStyle: symbol (default) [source,ruby] ---- # bad describe 'Something', {} # good describe 'Something' ---- [#references-rspecemptymetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyMetadata [#rspecemptyoutput] == RSpec/EmptyOutput |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.29 | - |=== Check that the `output` matcher is not called with an empty string. [#examples-rspecemptyoutput] === Examples [source,ruby] ---- # bad expect { foo }.to output('').to_stdout expect { bar }.not_to output('').to_stderr # good expect { foo }.not_to output.to_stdout expect { bar }.to output.to_stderr ---- [#references-rspecemptyoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyOutput [#rspeceq] == RSpec/Eq |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.24 | - |=== Use `eq` instead of `be ==` to compare objects. [#examples-rspeceq] === Examples [source,ruby] ---- # bad expect(foo).to be == 42 # good expect(foo).to eq 42 ---- [#references-rspeceq] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Eq [#rspecexamplelength] == RSpec/ExampleLength |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.5 | 2.3 |=== Checks for long examples. A long example is usually more difficult to understand. Consider extracting out some behavior, e.g. with a `let` block, or a helper method. You can set constructs you want to fold with `CountAsOne`. Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct will be counted as one line regardless of its actual size. [#examples-rspecexamplelength] === Examples [source,ruby] ---- # bad it do service = described_class.new more_setup more_setup result = service.call expect(result).to be(true) end # good it do service = described_class.new result = service.call expect(result).to be(true) end ---- [#countasone_-__array__-_heredoc__-_method_call__-rspecexamplelength] ==== CountAsOne: ['array', 'heredoc', 'method_call'] [source,ruby] ---- it do array = [ # +1 1, 2 ] hash = { # +3 key: 'value' } msg = <<~HEREDOC # +1 Heredoc content. HEREDOC foo( # +1 1, 2 ) end # 6 points ---- [#configurable-attributes-rspecexamplelength] === Configurable attributes |=== | Name | Default value | Configurable values | Max | `5` | Integer | CountAsOne | `[]` | Array |=== [#references-rspecexamplelength] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength [#rspecexamplewithoutdescription] == RSpec/ExampleWithoutDescription |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.22 | - |=== Checks for examples without a description. RSpec allows for auto-generated example descriptions when there is no description provided or the description is an empty one. It is acceptable to use `specify` without a description This cop removes empty descriptions. It also defines whether auto-generated description is allowed, based on the configured style. This cop can be configured using the `EnforcedStyle` option [#examples-rspecexamplewithoutdescription] === Examples [source,ruby] ---- # always good specify do result = service.call expect(result).to be(true) end ---- [#_enforcedstyle_-always_allow_-_default_-rspecexamplewithoutdescription] ==== `EnforcedStyle: always_allow` (default) [source,ruby] ---- # bad it('') { is_expected.to be_good } specify '' do result = service.call expect(result).to be(true) end # good it { is_expected.to be_good } specify do result = service.call expect(result).to be(true) end ---- [#_enforcedstyle_-single_line_only_-rspecexamplewithoutdescription] ==== `EnforcedStyle: single_line_only` [source,ruby] ---- # bad it('') { is_expected.to be_good } it do result = service.call expect(result).to be(true) end # good it { is_expected.to be_good } ---- [#_enforcedstyle_-disallow_-rspecexamplewithoutdescription] ==== `EnforcedStyle: disallow` [source,ruby] ---- # bad it { is_expected.to be_good } it do result = service.call expect(result).to be(true) end ---- [#configurable-attributes-rspecexamplewithoutdescription] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `always_allow` | `always_allow`, `single_line_only`, `disallow` |=== [#references-rspecexamplewithoutdescription] === References * https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription [#rspecexamplewording] == RSpec/ExampleWording |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.0 | 2.13 |=== Checks for common mistakes in example descriptions. This cop will correct docstrings that begin with 'should' and 'it'. This cop will also look for insufficient examples and call them out. Use the DisallowedExamples setting to prevent unclear or insufficient descriptions. Please note that this config will not be treated as case sensitive. [#safety-rspecexamplewording] === Safety The autocorrect is experimental - use with care! It can be configured with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only). While the autocorrect will not break your code (it only modifies test description strings, not the actual test logic), it may produce grammatically incorrect English in some cases. Always review the diff when using autocorrect to ensure the descriptions remain natural and accurate. This is not classified as an unsafe autocorrect because it does not affect code behavior, but manual review of changes is strongly recommended. [#examples-rspecexamplewording] === Examples [source,ruby] ---- # bad it 'should find nothing' do end it 'will find nothing' do end # good it 'finds nothing' do end ---- [source,ruby] ---- # bad it 'it does things' do end # good it 'does things' do end ---- [#_disallowedexamples_-__works___-_default_-rspecexamplewording] ==== `DisallowedExamples: ['works']` (default) [source,ruby] ---- # bad it 'works' do end # good it 'marks the task as done' do end ---- [#configurable-attributes-rspecexamplewording] === Configurable attributes |=== | Name | Default value | Configurable values | CustomTransform | `{"be" => "is", "BE" => "IS", "have" => "has", "HAVE" => "HAS"}` | | IgnoredWords | `[]` | Array | DisallowedExamples | `works` | Array |=== [#references-rspecexamplewording] === References * https://rspec.rubystyle.guide/#should-in-example-docstrings * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording * http://betterspecs.org/#should [#rspecexcessivedocstringspacing] == RSpec/ExcessiveDocstringSpacing |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.5 | - |=== Checks for excessive whitespace in example descriptions. [#examples-rspecexcessivedocstringspacing] === Examples [source,ruby] ---- # bad it ' has excessive spacing ' do end # good it 'has excessive spacing' do end ---- [source,ruby] ---- # bad context ' when a condition is met ' do end # good context 'when a condition is met' do end ---- [#references-rspecexcessivedocstringspacing] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExcessiveDocstringSpacing [#rspecexpectactual] == RSpec/ExpectActual |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.7 | 2.23 |=== Checks for `expect(...)` calls containing literal values. Autocorrection is performed when the expected is not a literal. [#examples-rspecexpectactual] === Examples [source,ruby] ---- # bad expect(5).to eq(price) expect(/foo/).to eq(pattern) expect("John").to eq(name) # good expect(price).to eq(5) expect(pattern).to eq(/foo/) expect(name).to eq("John") # bad (not supported autocorrection) expect(false).to eq(true) ---- [#configurable-attributes-rspecexpectactual] === Configurable attributes |=== | Name | Default value | Configurable values | Exclude | `+**/spec/routing/**/*+` | Array |=== [#references-rspecexpectactual] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual [#rspecexpectchange] == RSpec/ExpectChange |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always (Unsafe) | 1.22 | 2.5 |=== Checks for consistent style of change matcher. Enforces either passing a receiver and message as method arguments, or a block. This cop can be configured using the `EnforcedStyle` option. [#safety-rspecexpectchange] === Safety Autocorrection is unsafe because `method_call` style calls the receiver *once* and sends the message to it before and after calling the `expect` block, whereas `block` style calls the expression *twice*, including the receiver. If your receiver is dynamic (e.g., the result of a method call) and you expect it to be called before and after the `expect` block, changing from `block` to `method_call` style may break your test. [source,ruby] ---- expect { run }.to change { my_method.message } # `my_method` is called before and after `run` expect { run }.to change(my_method, :message) # `my_method` is called once, but `message` is called on it twice ---- [#examples-rspecexpectchange] === Examples [#_enforcedstyle_-method_call_-_default_-rspecexpectchange] ==== `EnforcedStyle: method_call` (default) [source,ruby] ---- # bad expect { run }.to change { Foo.bar } expect { run }.to change { foo.baz } # good expect { run }.to change(Foo, :bar) expect { run }.to change(foo, :baz) # also good when there are arguments or chained method calls expect { run }.to change { Foo.bar(:count) } expect { run }.to change { user.reload.name } ---- [#_enforcedstyle_-block_-rspecexpectchange] ==== `EnforcedStyle: block` [source,ruby] ---- # bad expect { run }.to change(Foo, :bar) # good expect { run }.to change { Foo.bar } ---- [#configurable-attributes-rspecexpectchange] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `method_call` | `method_call`, `block` |=== [#references-rspecexpectchange] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange [#rspecexpectinhook] == RSpec/ExpectInHook |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.16 | - |=== Do not use `expect` in hooks such as `before`. [#examples-rspecexpectinhook] === Examples [source,ruby] ---- # bad before do expect(something).to eq 'foo' end # bad after do expect_any_instance_of(Something).to receive(:foo) end # good it do expect(something).to eq 'foo' end ---- [#references-rspecexpectinhook] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook [#rspecexpectinlet] == RSpec/ExpectInLet |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.30 | - |=== Do not use `expect` in let. [#examples-rspecexpectinlet] === Examples [source,ruby] ---- # bad let(:foo) do expect(something).to eq 'foo' end # good it do expect(something).to eq 'foo' end ---- [#references-rspecexpectinlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInLet [#rspecexpectoutput] == RSpec/ExpectOutput |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.10 | - |=== Checks for opportunities to use `expect { ... }.to output`. [#examples-rspecexpectoutput] === Examples [source,ruby] ---- # bad $stdout = StringIO.new my_app.print_report $stdout = STDOUT expect($stdout.string).to eq('Hello World') # good expect { my_app.print_report }.to output('Hello World').to_stdout ---- [#references-rspecexpectoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectOutput [#rspecfocus] == RSpec/Focus |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 1.5 | 2.31 |=== Checks if examples are focused. This cop does not support autocorrection in some cases. [#examples-rspecfocus] === Examples [source,ruby] ---- # bad describe MyClass, focus: true do end describe MyClass, :focus do end fdescribe MyClass do end # good describe MyClass do end # bad fdescribe 'test' do; end # good describe 'test' do; end # bad shared_examples 'test', focus: true do; end # good shared_examples 'test' do; end # bad shared_context 'test', focus: true do; end # good shared_context 'test' do; end # bad (does not support autocorrection) focus 'test' do; end ---- [#references-rspecfocus] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Focus [#rspechookargument] == RSpec/HookArgument |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.7 | - |=== Checks the arguments passed to `before`, `around`, and `after`. This cop checks for consistent style when specifying RSpec hooks which run for each example. There are three supported styles: "implicit", "each", and "example." All styles have the same behavior. [#examples-rspechookargument] === Examples [#_enforcedstyle_-implicit_-_default_-rspechookargument] ==== `EnforcedStyle: implicit` (default) [source,ruby] ---- # bad before(:each) do # ... end # bad before(:example) do # ... end # good before do # ... end ---- [#_enforcedstyle_-each_-rspechookargument] ==== `EnforcedStyle: each` [source,ruby] ---- # bad before(:example) do # ... end # bad before do # ... end # good before(:each) do # ... end ---- [#_enforcedstyle_-example_-rspechookargument] ==== `EnforcedStyle: example` [source,ruby] ---- # bad before(:each) do # ... end # bad before do # ... end # good before(:example) do # ... end ---- [#configurable-attributes-rspechookargument] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `implicit` | `implicit`, `each`, `example` |=== [#references-rspechookargument] === References * https://rspec.rubystyle.guide/#redundant-beforeeach * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument [#rspechooksbeforeexamples] == RSpec/HooksBeforeExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 1.29 | 2.31 |=== Checks for before/around/after hooks that come after an example. [#examples-rspechooksbeforeexamples] === Examples [source,ruby] ---- # bad it 'checks what foo does' do expect(foo).to be end before { prepare } after { clean_up } # good before { prepare } after { clean_up } it 'checks what foo does' do expect(foo).to be end ---- [#references-rspechooksbeforeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples [#rspecidenticalequalityassertion] == RSpec/IdenticalEqualityAssertion |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.4 | - |=== Checks for equality assertions with identical expressions on both sides. [#examples-rspecidenticalequalityassertion] === Examples [source,ruby] ---- # bad expect(foo.bar).to eq(foo.bar) expect(foo.bar).to eql(foo.bar) # good expect(foo.bar).to eq(2) expect(foo.bar).to eql(2) ---- [#references-rspecidenticalequalityassertion] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion [#rspecimplicitblockexpectation] == RSpec/ImplicitBlockExpectation |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.35 | - |=== Check that implicit block expectation syntax is not used. Prefer using explicit block expectations. [#examples-rspecimplicitblockexpectation] === Examples [source,ruby] ---- # bad subject { -> { do_something } } it { is_expected.to change(something).to(new_value) } # good it 'changes something to a new value' do expect { do_something }.to change(something).to(new_value) end ---- [#references-rspecimplicitblockexpectation] === References * https://rspec.rubystyle.guide/#implicit-block-expectations * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitBlockExpectation [#rspecimplicitexpect] == RSpec/ImplicitExpect |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.8 | - |=== Check that a consistent implicit expectation style is used. This cop can be configured using the `EnforcedStyle` option and supports the `--auto-gen-config` flag. [#examples-rspecimplicitexpect] === Examples [#_enforcedstyle_-is_expected_-_default_-rspecimplicitexpect] ==== `EnforcedStyle: is_expected` (default) [source,ruby] ---- # bad it { should be_truthy } # good it { is_expected.to be_truthy } ---- [#_enforcedstyle_-should_-rspecimplicitexpect] ==== `EnforcedStyle: should` [source,ruby] ---- # bad it { is_expected.to be_truthy } # good it { should be_truthy } ---- [#configurable-attributes-rspecimplicitexpect] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `is_expected` | `is_expected`, `should` |=== [#references-rspecimplicitexpect] === References * https://rspec.rubystyle.guide/#use-expect * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect [#rspecimplicitsubject] == RSpec/ImplicitSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.29 | 2.13 |=== Checks for usage of implicit subject (`is_expected` / `should`). This cop can be configured using the `EnforcedStyle` option [#examples-rspecimplicitsubject] === Examples [#_enforcedstyle_-single_line_only_-_default_-rspecimplicitsubject] ==== `EnforcedStyle: single_line_only` (default) [source,ruby] ---- # bad it do is_expected.to be_truthy end # good it { is_expected.to be_truthy } it do expect(subject).to be_truthy end ---- [#_enforcedstyle_-single_statement_only_-rspecimplicitsubject] ==== `EnforcedStyle: single_statement_only` [source,ruby] ---- # bad it do foo = 1 is_expected.to be_truthy end # good it do foo = 1 expect(subject).to be_truthy end it do is_expected.to be_truthy end ---- [#_enforcedstyle_-disallow_-rspecimplicitsubject] ==== `EnforcedStyle: disallow` [source,ruby] ---- # bad it { is_expected.to be_truthy } # good it { expect(subject).to be_truthy } ---- [#_enforcedstyle_-require_implicit_-rspecimplicitsubject] ==== `EnforcedStyle: require_implicit` [source,ruby] ---- # bad it { expect(subject).to be_truthy } # good it { is_expected.to be_truthy } # bad it do expect(subject).to be_truthy end # good it do is_expected.to be_truthy end # good it { expect(named_subject).to be_truthy } ---- [#configurable-attributes-rspecimplicitsubject] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `single_line_only` | `single_line_only`, `single_statement_only`, `disallow`, `require_implicit` |=== [#references-rspecimplicitsubject] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject [#rspecincludeexamples] == RSpec/IncludeExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Always (Unsafe) | 3.6 | 3.7 |=== Checks for usage of `include_examples`. `include_examples`, unlike `it_behaves_like`, does not create its own context. As such, using `subject`, `let`, `before`/`after`, etc. within shared examples included with `include_examples` can have unexpected behavior and side effects. Prefer using `it_behaves_like` instead. [#safety-rspecincludeexamples] === Safety `include_examples` and `it_behaves_like` have different scoping behaviors. Changing `include_examples` to `it_behaves_like` creates a new context, altering setup dependencies, which can lead to unexpected test failures. Specifically, the scope of hooks (`before`, `after`, `around`) changes, which may prevent expected setup from being inherited correctly. Additionally, `let` and `subject` are affected by scoping rules. When `include_examples` is used, `let` and `subject` defined within `shared_examples` are evaluated in the caller's context, allowing access to their values. In contrast, `it_behaves_like` creates a new context, preventing access to `let` or `subject` values from the caller's context. [source,ruby] ---- shared_examples "mock behavior" do before do allow(service).to receive(:call).and_return("mocked response") end it "returns mocked response" do expect(service.call).to eq "mocked response" end end context "working example with include_examples" do let(:service) { double(:service) } include_examples "mock behavior" it "uses the mocked service" do expect(service.call).to eq "mocked response" # Passes end end context "broken example with it_behaves_like" do let(:service) { double(:service) } it_behaves_like "mock behavior" it "unexpectedly does not use the mocked service" do # Fails because `it_behaves_like` does not apply the mock setup expect(service.call).to eq "mocked response" end end ---- [#examples-rspecincludeexamples] === Examples [source,ruby] ---- # bad include_examples 'examples' # good it_behaves_like 'examples' ---- [#references-rspecincludeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IncludeExamples [#rspecindexedlet] == RSpec/IndexedLet |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.20 | 2.23 |=== Do not set up test data using indexes (e.g., `item_1`, `item_2`). It makes reading the test harder because it's not clear what exactly is tested by this particular example. The configurable options `AllowedIdentifiers` and `AllowedPatterns` will also read those set in `Naming/VariableNumber`. [#examples-rspecindexedlet] === Examples [#_max_-1-_default__-rspecindexedlet] ==== `Max: 1 (default)` [source,ruby] ---- # bad let(:item_1) { create(:item) } let(:item_2) { create(:item) } let(:item1) { create(:item) } let(:item2) { create(:item) } # good let(:visible_item) { create(:item, visible: true) } let(:invisible_item) { create(:item, visible: false) } ---- [#_max_-2_-rspecindexedlet] ==== `Max: 2` [source,ruby] ---- # bad let(:item_1) { create(:item) } let(:item_2) { create(:item) } let(:item_3) { create(:item) } # good let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- [#_allowedidentifiers_-__item_1__-_item_2___-rspecindexedlet] ==== `AllowedIdentifiers: ['item_1', 'item_2']` [source,ruby] ---- # good let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- [#_allowedpatterns_-__item___-rspecindexedlet] ==== `AllowedPatterns: ['item']` [source,ruby] ---- # good let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- [#configurable-attributes-rspecindexedlet] === Configurable attributes |=== | Name | Default value | Configurable values | Max | `1` | Integer | AllowedIdentifiers | `[]` | Array | AllowedPatterns | `[]` | Array |=== [#references-rspecindexedlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IndexedLet [#rspecinstancespy] == RSpec/InstanceSpy |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.12 | - |=== Checks for `instance_double` used with `have_received`. [#examples-rspecinstancespy] === Examples [source,ruby] ---- # bad it do foo = instance_double(Foo).as_null_object expect(foo).to have_received(:bar) end # good it do foo = instance_spy(Foo) expect(foo).to have_received(:bar) end ---- [#references-rspecinstancespy] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceSpy [#rspecinstancevariable] == RSpec/InstanceVariable |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.0 | 1.7 |=== Checks for instance variable usage in specs. This cop can be configured with the option `AssignmentOnly` which will configure the cop to only register offenses on instance variable usage if the instance variable is also assigned within the spec [#examples-rspecinstancevariable] === Examples [source,ruby] ---- # bad describe MyClass do before { @foo = [] } it { expect(@foo).to be_empty } end # good describe MyClass do let(:foo) { [] } it { expect(foo).to be_empty } end ---- [#with-assignmentonly-configuration-rspecinstancevariable] ==== with AssignmentOnly configuration [source,ruby] ---- # rubocop.yml # RSpec/InstanceVariable: # AssignmentOnly: true # bad describe MyClass do before { @foo = [] } it { expect(@foo).to be_empty } end # allowed describe MyClass do it { expect(@foo).to be_empty } end # good describe MyClass do let(:foo) { [] } it { expect(foo).to be_empty } end ---- [#configurable-attributes-rspecinstancevariable] === Configurable attributes |=== | Name | Default value | Configurable values | AssignmentOnly | `false` | Boolean |=== [#references-rspecinstancevariable] === References * https://rspec.rubystyle.guide/#instance-variables * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable [#rspecisexpectedspecify] == RSpec/IsExpectedSpecify |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.27 | - |=== Check for `specify` with `is_expected` and one-liner expectations. [#examples-rspecisexpectedspecify] === Examples [source,ruby] ---- # bad specify { is_expected.to be_truthy } # good it { is_expected.to be_truthy } # good specify do # ... end specify { expect(sqrt(4)).to eq(2) } ---- [#references-rspecisexpectedspecify] === References * https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IsExpectedSpecify [#rspecitbehaveslike] == RSpec/ItBehavesLike |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.13 | - |=== Checks that only one `it_behaves_like` style is used. [#examples-rspecitbehaveslike] === Examples [#_enforcedstyle_-it_behaves_like_-_default_-rspecitbehaveslike] ==== `EnforcedStyle: it_behaves_like` (default) [source,ruby] ---- # bad it_should_behave_like 'a foo' # good it_behaves_like 'a foo' ---- [#_enforcedstyle_-it_should_behave_like_-rspecitbehaveslike] ==== `EnforcedStyle: it_should_behave_like` [source,ruby] ---- # bad it_behaves_like 'a foo' # good it_should_behave_like 'a foo' ---- [#configurable-attributes-rspecitbehaveslike] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `it_behaves_like` | `it_behaves_like`, `it_should_behave_like` |=== [#references-rspecitbehaveslike] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike [#rspeciteratedexpectation] == RSpec/IteratedExpectation |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.14 | - |=== Check that `all` matcher is used instead of iterating over an array. [#examples-rspeciteratedexpectation] === Examples [source,ruby] ---- # bad it 'validates users' do [user1, user2, user3].each { |user| expect(user).to be_valid } end # good it 'validates users' do expect([user1, user2, user3]).to all(be_valid) end ---- [#references-rspeciteratedexpectation] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IteratedExpectation [#rspecleadingsubject] == RSpec/LeadingSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.7 | 1.14 |=== Enforce that subject is the first definition in the test. [#examples-rspecleadingsubject] === Examples [source,ruby] ---- # bad let(:params) { blah } subject { described_class.new(params) } before { do_something } subject { described_class.new(params) } it { expect_something } subject { described_class.new(params) } it { expect_something_else } # good subject { described_class.new(params) } let(:params) { blah } # good subject { described_class.new(params) } before { do_something } # good subject { described_class.new(params) } it { expect_something } it { expect_something_else } ---- [#references-rspecleadingsubject] === References * https://rspec.rubystyle.guide/#leading-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject [#rspecleakyconstantdeclaration] == RSpec/LeakyConstantDeclaration |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.35 | - |=== Checks that no class, module, or constant is declared. Constants, including classes and modules, when declared in a block scope, are defined in global namespace, and leak between examples. If several examples may define a `DummyClass`, instead of being a blank slate class as it will be in the first example, subsequent examples will be reopening it and modifying its behavior in unpredictable ways. Even worse when a class that exists in the codebase is reopened. Anonymous classes are fine, since they don't result in global namespace name clashes. [#examples-rspecleakyconstantdeclaration] === Examples [#constants-leak-between-examples-rspecleakyconstantdeclaration] ==== Constants leak between examples [source,ruby] ---- # bad describe SomeClass do OtherClass = Struct.new CONSTANT_HERE = 'I leak into global namespace' end # good describe SomeClass do before do stub_const('OtherClass', Struct.new) stub_const('CONSTANT_HERE', 'I only exist during this example') end end ---- [source,ruby] ---- # bad describe SomeClass do class FooClass < described_class def double_that some_base_method * 2 end end it { expect(FooClass.new.double_that).to eq(4) } end # good - anonymous class, no constant needs to be defined describe SomeClass do let(:foo_class) do Class.new(described_class) do def double_that some_base_method * 2 end end end it { expect(foo_class.new.double_that).to eq(4) } end # good - constant is stubbed describe SomeClass do before do foo_class = Class.new(described_class) do def do_something end end stub_const('FooClass', foo_class) end it { expect(FooClass.new.double_that).to eq(4) } end ---- [source,ruby] ---- # bad describe SomeClass do module SomeModule class SomeClass def do_something end end end end # good describe SomeClass do before do foo_class = Class.new(described_class) do def do_something end end stub_const('SomeModule::SomeClass', foo_class) end end ---- [#references-rspecleakyconstantdeclaration] === References * https://rspec.rubystyle.guide/#declare-constants * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration * https://rspec.info/features/3-12/rspec-mocks/mutating-constants [#rspecleakylocalvariable] == RSpec/LeakyLocalVariable |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | No | 3.8 | - |=== Checks for local variables from outer scopes used inside examples. Local variables assigned outside an example but used within it act as shared state, which can make tests non-deterministic. [#examples-rspecleakylocalvariable] === Examples [source,ruby] ---- # bad - outside variable used in a hook user = create(:user) before { user.update(admin: true) } # good let(:user) { create(:user) } before { user.update(admin: true) } # bad - outside variable used in an example user = create(:user) it 'is persisted' do expect(user).to be_persisted end # good let(:user) { create(:user) } it 'is persisted' do expect(user).to be_persisted end # also good - assigning the variable within the example it 'is persisted' do user = create(:user) expect(user).to be_persisted end # bad - outside variable passed to included examples attrs = ['foo', 'bar'] it_behaves_like 'some examples', attrs # good it_behaves_like 'some examples' do let(:attrs) { ['foo', 'bar'] } end # good - when variable is used only as example description attribute = 'foo' it "#{attribute} is persisted" do expectations end # good - when variable is used only in example metadata skip_message = 'not yet implemented' it 'does something', skip: skip_message do expectations end # good - when variable is used only to include other examples examples = foo ? 'some examples' : 'other examples' it_behaves_like examples, another_argument ---- [#references-rspecleakylocalvariable] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyLocalVariable [#rspecletbeforeexamples] == RSpec/LetBeforeExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 1.16 | 2.31 |=== Checks for `let` definitions that come after an example. [#examples-rspecletbeforeexamples] === Examples [source,ruby] ---- # bad let(:foo) { bar } it 'checks what foo does' do expect(foo).to be end let(:some) { other } it 'checks what some does' do expect(some).to be end # good let(:foo) { bar } let(:some) { other } it 'checks what foo does' do expect(foo).to be end it 'checks what some does' do expect(some).to be end ---- [#references-rspecletbeforeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetBeforeExamples [#rspecletsetup] == RSpec/LetSetup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.7 | - |=== Checks unreferenced `let!` calls being used for test setup. [#examples-rspecletsetup] === Examples [source,ruby] ---- # bad let!(:my_widget) { create(:widget) } it 'counts widgets' do expect(Widget.count).to eq(1) end # good it 'counts widgets' do create(:widget) expect(Widget.count).to eq(1) end # good before { create(:widget) } it 'counts widgets' do expect(Widget.count).to eq(1) end # good describe 'a widget' do let!(:my_widget) { create(:widget) } context 'when visiting its page' do let!(:my_widget) { create(:widget, name: 'Special') } it 'counts widgets' do expect(Widget.count).to eq(1) end end end ---- [#references-rspecletsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetSetup [#rspecmatcharray] == RSpec/MatchArray |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.19 | - |=== Checks where `match_array` is used. This cop checks for the following: - Prefer `contain_exactly` when matching an array with values. - Prefer `eq` when using `match_array` with an empty array literal. [#examples-rspecmatcharray] === Examples [source,ruby] ---- # bad it { is_expected.to match_array([content1, content2]) } # good it { is_expected.to contain_exactly(content1, content2) } # good it { is_expected.to match_array([content] + array) } # good it { is_expected.to match_array(%w(tremble in fear foolish mortals)) } ---- [#references-rspecmatcharray] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MatchArray [#rspecmessagechain] == RSpec/MessageChain |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.7 | - |=== Check that chains of messages are not being stubbed. [#examples-rspecmessagechain] === Examples [source,ruby] ---- # bad allow(foo).to receive_message_chain(:bar, :baz).and_return(42) # good thing = Thing.new(baz: 42) allow(foo).to receive(:bar).and_return(thing) ---- [#references-rspecmessagechain] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageChain [#rspecmessageexpectation] == RSpec/MessageExpectation |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | No | 1.7 | 1.8 |=== Checks for consistent message expectation style. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. [#examples-rspecmessageexpectation] === Examples [#_enforcedstyle_-allow_-_default_-rspecmessageexpectation] ==== `EnforcedStyle: allow` (default) [source,ruby] ---- # bad expect(foo).to receive(:bar) # good allow(foo).to receive(:bar) ---- [#_enforcedstyle_-expect_-rspecmessageexpectation] ==== `EnforcedStyle: expect` [source,ruby] ---- # bad allow(foo).to receive(:bar) # good expect(foo).to receive(:bar) ---- [#configurable-attributes-rspecmessageexpectation] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `allow` | `allow`, `expect` |=== [#references-rspecmessageexpectation] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageExpectation [#rspecmessagespies] == RSpec/MessageSpies |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.9 | - |=== Checks that message expectations are set using spies. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. [#examples-rspecmessagespies] === Examples [#_enforcedstyle_-have_received_-_default_-rspecmessagespies] ==== `EnforcedStyle: have_received` (default) [source,ruby] ---- # bad expect(foo).to receive(:bar) do_something # good allow(foo).to receive(:bar) # or use instance_spy do_something expect(foo).to have_received(:bar) ---- [#_enforcedstyle_-receive_-rspecmessagespies] ==== `EnforcedStyle: receive` [source,ruby] ---- # bad allow(foo).to receive(:bar) do_something expect(foo).to have_received(:bar) # good expect(foo).to receive(:bar) do_something ---- [#configurable-attributes-rspecmessagespies] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `have_received` | `have_received`, `receive` |=== [#references-rspecmessagespies] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies [#rspecmetadatastyle] == RSpec/MetadataStyle |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.24 | - |=== Use consistent metadata style. This cop does not support autocorrection in the case of `EnforcedStyle: hash` where the trailing metadata type is ambiguous. (e.g. `describe 'Something', :a, b`) [#examples-rspecmetadatastyle] === Examples [#enforcedstyle_-symbol-_default_-rspecmetadatastyle] ==== EnforcedStyle: symbol (default) [source,ruby] ---- # bad describe 'Something', a: true # good describe 'Something', :a ---- [#enforcedstyle_-hash-rspecmetadatastyle] ==== EnforcedStyle: hash [source,ruby] ---- # bad describe 'Something', :a # good describe 'Something', a: true ---- [#configurable-attributes-rspecmetadatastyle] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `symbol` | `hash`, `symbol` |=== [#references-rspecmetadatastyle] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MetadataStyle [#rspecmissingexamplegroupargument] == RSpec/MissingExampleGroupArgument |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.28 | - |=== Checks that the first argument to an example group is not empty. [#examples-rspecmissingexamplegroupargument] === Examples [source,ruby] ---- # bad describe do end RSpec.describe do end # good describe TestedClass do end describe "A feature example" do end ---- [#references-rspecmissingexamplegroupargument] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument [#rspecmissingexpectationtargetmethod] == RSpec/MissingExpectationTargetMethod |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 3.0 | - |=== Checks if `.to`, `not_to` or `to_not` are used. The RSpec::Expectations::ExpectationTarget must use `to`, `not_to` or `to_not` to run. Therefore, this cop checks if other methods are used. [#examples-rspecmissingexpectationtargetmethod] === Examples [source,ruby] ---- # bad expect(something).kind_of? Foo is_expected == 42 expect{something}.eq? BarError # good expect(something).to be_a Foo is_expected.to eq 42 expect{something}.to raise_error BarError ---- [#references-rspecmissingexpectationtargetmethod] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExpectationTargetMethod [#rspecmultipledescribes] == RSpec/MultipleDescribes |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.0 | - |=== Checks for multiple top-level example groups. Multiple descriptions for the same class or module should either be nested or separated into different test files. [#examples-rspecmultipledescribes] === Examples [source,ruby] ---- # bad describe MyClass, '.do_something' do end describe MyClass, '.do_something_else' do end # good describe MyClass do describe '.do_something' do end describe '.do_something_else' do end end ---- [#references-rspecmultipledescribes] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes [#rspecmultipleexpectations] == RSpec/MultipleExpectations |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.7 | 1.21 |=== Checks if examples contain too many `expect` calls. This cop is configurable using the `Max` option and works with `--auto-gen-config`. [#examples-rspecmultipleexpectations] === Examples [source,ruby] ---- # bad describe UserCreator do it 'builds a user' do expect(user.name).to eq("John") expect(user.age).to eq(22) end end # good describe UserCreator do it 'sets the users name' do expect(user.name).to eq("John") end it 'sets the users age' do expect(user.age).to eq(22) end end ---- [#_aggregate_failures_-true_-_default_-rspecmultipleexpectations] ==== `aggregate_failures: true` (default) [source,ruby] ---- # good - the cop ignores when RSpec aggregates failures describe UserCreator do it 'builds a user', :aggregate_failures do expect(user.name).to eq("John") expect(user.age).to eq(22) end end ---- [#_aggregate_failures_-false_-rspecmultipleexpectations] ==== `aggregate_failures: false` [source,ruby] ---- # Detected as an offense describe UserCreator do it 'builds a user', aggregate_failures: false do expect(user.name).to eq("John") expect(user.age).to eq(22) end end ---- [#_max_-1_-_default_-rspecmultipleexpectations] ==== `Max: 1` (default) [source,ruby] ---- # bad describe UserCreator do it 'builds a user' do expect(user.name).to eq("John") expect(user.age).to eq(22) end end ---- [#_max_-2_-rspecmultipleexpectations] ==== `Max: 2` [source,ruby] ---- # good describe UserCreator do it 'builds a user' do expect(user.name).to eq("John") expect(user.age).to eq(22) end end ---- [#configurable-attributes-rspecmultipleexpectations] === Configurable attributes |=== | Name | Default value | Configurable values | Max | `1` | Integer |=== [#references-rspecmultipleexpectations] === References * https://rspec.rubystyle.guide/#expectation-per-example * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations * http://betterspecs.org/#single [#rspecmultiplememoizedhelpers] == RSpec/MultipleMemoizedHelpers |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.43 | - |=== Checks if example groups contain too many `let` and `subject` calls. This cop is configurable using the `Max` option and the `AllowSubject` which will configure the cop to only register offenses on calls to `let` and not calls to `subject`. [#examples-rspecmultiplememoizedhelpers] === Examples [source,ruby] ---- # bad describe MyClass do let(:foo) { [] } let(:bar) { [] } let!(:baz) { [] } let(:qux) { [] } let(:quux) { [] } let(:quuz) { {} } end describe MyClass do let(:foo) { [] } let(:bar) { [] } let!(:baz) { [] } context 'when stuff' do let(:qux) { [] } let(:quux) { [] } let(:quuz) { {} } end end # good describe MyClass do let(:bar) { [] } let!(:baz) { [] } let(:qux) { [] } let(:quux) { [] } let(:quuz) { {} } end describe MyClass do context 'when stuff' do let(:foo) { [] } let(:bar) { [] } let!(:booger) { [] } end context 'when other stuff' do let(:qux) { [] } let(:quux) { [] } let(:quuz) { {} } end end ---- [#when-disabling-allowsubject-configuration-rspecmultiplememoizedhelpers] ==== when disabling AllowSubject configuration [source,ruby] ---- # rubocop.yml # RSpec/MultipleMemoizedHelpers: # AllowSubject: false # bad - `subject` counts towards memoized helpers describe MyClass do subject { {} } let(:foo) { [] } let(:bar) { [] } let!(:baz) { [] } let(:qux) { [] } let(:quux) { [] } end ---- [#with-max-configuration-rspecmultiplememoizedhelpers] ==== with Max configuration [source,ruby] ---- # rubocop.yml # RSpec/MultipleMemoizedHelpers: # Max: 1 # bad describe MyClass do let(:foo) { [] } let(:bar) { [] } end ---- [#configurable-attributes-rspecmultiplememoizedhelpers] === Configurable attributes |=== | Name | Default value | Configurable values | AllowSubject | `true` | Boolean | Max | `5` | Integer |=== [#references-rspecmultiplememoizedhelpers] === References * https://rspec.rubystyle.guide/#let-blocks * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers [#rspecmultiplesubjects] == RSpec/MultipleSubjects |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.16 | - |=== Checks if an example group defines `subject` multiple times. This cop does not support autocorrection in some cases. The autocorrect behavior for this cop depends on the type of duplication: - If multiple named subjects are defined then this probably indicates that the overwritten subjects (all subjects except the last definition) are effectively being used to define helpers. In this case they are replaced with `let`. - If multiple unnamed subjects are defined though then this can *only* be dead code and we remove the overwritten subject definitions. - If subjects are defined with `subject!` then we don't autocorrect. This is enough of an edge case that people can just move this to a `before` hook on their own [#examples-rspecmultiplesubjects] === Examples [source,ruby] ---- # bad describe Foo do subject(:user) { User.new } subject(:post) { Post.new } end # good describe Foo do let(:user) { User.new } subject(:post) { Post.new } end # bad (does not support autocorrection) describe Foo do subject!(:user) { User.new } subject!(:post) { Post.new } end # good describe Foo do before do User.new Post.new end end ---- [#references-rspecmultiplesubjects] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleSubjects [#rspecnamedsubject] == RSpec/NamedSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.5.3 | 2.15 |=== Checks for explicitly referenced test subjects. RSpec lets you declare an "implicit subject" using `subject { ... }` which allows for tests like `it { is_expected.to be_valid }`. If you need to reference your test subject you should explicitly name it using `subject(:your_subject_name) { ... }`. Your test subjects should be the most important object in your tests so they deserve a descriptive name. This cop can be configured in your configuration using `EnforcedStyle`, and `IgnoreSharedExamples` which will not report offenses for implicit subjects in shared example groups. [#examples-rspecnamedsubject] === Examples [#_enforcedstyle_-always_-_default_-rspecnamedsubject] ==== `EnforcedStyle: always` (default) [source,ruby] ---- # bad RSpec.describe User do subject { described_class.new } it 'is valid' do expect(subject.valid?).to be(true) end end # good RSpec.describe User do subject(:user) { described_class.new } it 'is valid' do expect(user.valid?).to be(true) end end # also good RSpec.describe User do subject(:user) { described_class.new } it { is_expected.to be_valid } end ---- [#_enforcedstyle_-named_only_-rspecnamedsubject] ==== `EnforcedStyle: named_only` [source,ruby] ---- # bad RSpec.describe User do subject(:user) { described_class.new } it 'is valid' do expect(subject.valid?).to be(true) end end # good RSpec.describe User do subject(:user) { described_class.new } it 'is valid' do expect(user.valid?).to be(true) end end # also good RSpec.describe User do subject { described_class.new } it { is_expected.to be_valid } end # acceptable RSpec.describe User do subject { described_class.new } it 'is valid' do expect(subject.valid?).to be(true) end end ---- [#configurable-attributes-rspecnamedsubject] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `always` | `always`, `named_only` | IgnoreSharedExamples | `true` | Boolean |=== [#references-rspecnamedsubject] === References * https://rspec.rubystyle.guide/#use-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject [#rspecnestedgroups] == RSpec/NestedGroups |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.7 | 2.13 |=== Checks for nested example groups. This cop is configurable using the `Max` option and supports `--auto-gen-config`. [#examples-rspecnestedgroups] === Examples [source,ruby] ---- # bad context 'when using some feature' do let(:some) { :various } let(:feature) { :setup } context 'when user is signed in' do # flagged by rubocop let(:user) do UserCreate.call(user_attributes) end let(:user_attributes) do { name: 'John', age: 22, role: role } end context 'when user is an admin' do # flagged by rubocop let(:role) { 'admin' } it 'blah blah' it 'yada yada' end end end # good context 'using some feature as an admin' do let(:some) { :various } let(:feature) { :setup } let(:user) do UserCreate.call( name: 'John', age: 22, role: 'admin' ) end it 'blah blah' it 'yada yada' end ---- [#_max_-3_-_default_-rspecnestedgroups] ==== `Max: 3` (default) [source,ruby] ---- # bad describe Foo do context 'foo' do context 'bar' do context 'baz' do # flagged by rubocop end end end end ---- [#_max_-2_-rspecnestedgroups] ==== `Max: 2` [source,ruby] ---- # bad describe Foo do context 'foo' do context 'bar' do # flagged by rubocop context 'baz' do # flagged by rubocop end end end end ---- [#_allowedgroups_-__-_default__-rspecnestedgroups] ==== `AllowedGroups: [] (default)` [source,ruby] ---- describe Foo do # <-- nested groups 1 context 'foo' do # <-- nested groups 2 context 'bar' do # <-- nested groups 3 end end end ---- [#_allowedgroups_-_path__-rspecnestedgroups] ==== `AllowedGroups: [path]` [source,ruby] ---- describe Foo do # <-- nested groups 1 path '/foo' do # <-- nested groups 1 (not counted) context 'bar' do # <-- nested groups 2 end end end ---- [#configurable-attributes-rspecnestedgroups] === Configurable attributes |=== | Name | Default value | Configurable values | Max | `3` | Integer | AllowedGroups | `[]` | Array |=== [#references-rspecnestedgroups] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups [#rspecnoexpectationexample] == RSpec/NoExpectationExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | No | No | 2.13 | 2.14 |=== Checks if an example contains any expectation. All RSpec's example and expectation methods are covered by default. If you are using your own custom methods, add the following configuration: RSpec: Language: Examples: Regular: - custom_it Expectations: - custom_expect This cop can be customized with an allowed expectation methods pattern with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed by default. [#examples-rspecnoexpectationexample] === Examples [source,ruby] ---- # bad it do a? end # good it do expect(a?).to be(true) end ---- [#_allowedpatterns_-configuration-rspecnoexpectationexample] ==== `AllowedPatterns` configuration [source,ruby] ---- # .rubocop.yml # RSpec/NoExpectationExample: # AllowedPatterns: # - ^expect_ # - ^assert_ ---- [source,ruby] ---- # bad it do not_expect_something end # good it do expect_something end it do assert_something end ---- [#configurable-attributes-rspecnoexpectationexample] === Configurable attributes |=== | Name | Default value | Configurable values | AllowedPatterns | `^expect_`, `^assert_` | Array |=== [#references-rspecnoexpectationexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample [#rspecnottonot] == RSpec/NotToNot |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.4 | - |=== Checks for consistent method usage for negating expectations. [#examples-rspecnottonot] === Examples [#_enforcedstyle_-not_to_-_default_-rspecnottonot] ==== `EnforcedStyle: not_to` (default) [source,ruby] ---- # bad it '...' do expect(false).to_not be_true end # good it '...' do expect(false).not_to be_true end ---- [#_enforcedstyle_-to_not_-rspecnottonot] ==== `EnforcedStyle: to_not` [source,ruby] ---- # bad it '...' do expect(false).not_to be_true end # good it '...' do expect(false).to_not be_true end ---- [#configurable-attributes-rspecnottonot] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `not_to` | `not_to`, `to_not` |=== [#references-rspecnottonot] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NotToNot [#rspecoutput] == RSpec/Output |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Command-line only (Unsafe) | 3.9 | - |=== Checks for the use of output calls like puts and print in specs. [#safety-rspecoutput] === Safety This autocorrection is marked as unsafe because, in rare cases, print statements can be used on purpose for integration testing and deleting them will cause tests to fail. [#examples-rspecoutput] === Examples [source,ruby] ---- # bad puts 'A debug message' pp 'A debug message' print 'A debug message' ---- [#references-rspecoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Output [#rspecoverwritingsetup] == RSpec/OverwritingSetup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.14 | - |=== Checks if there is a let/subject that overwrites an existing one. [#examples-rspecoverwritingsetup] === Examples [source,ruby] ---- # bad let(:foo) { bar } let(:foo) { baz } subject(:foo) { bar } let(:foo) { baz } let(:foo) { bar } let!(:foo) { baz } # good subject(:test) { something } let(:foo) { bar } let(:baz) { baz } let!(:other) { other } ---- [#references-rspecoverwritingsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup [#rspecpending] == RSpec/Pending |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | No | 1.25 | - |=== Checks for any pending or skipped examples. [#examples-rspecpending] === Examples [source,ruby] ---- # bad describe MyClass do it "should be true" end describe MyClass do it "should be true", skip: true do expect(1).to eq(2) end end describe MyClass do it "should be true" do pending end end describe MyClass do xit "should be true" do end end # good describe MyClass do end ---- [#references-rspecpending] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending [#rspecpendingwithoutreason] == RSpec/PendingWithoutReason |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.16 | - |=== Checks for pending or skipped examples without reason. [#examples-rspecpendingwithoutreason] === Examples [source,ruby] ---- # bad pending 'does something' do end # bad it 'does something', :pending do end # bad it 'does something' do pending end # bad xdescribe 'something' do end # bad skip 'does something' do end # bad it 'does something', :skip do end # bad it 'does something' do skip end # bad it 'does something' # good it 'does something' do pending 'reason' end # good it 'does something' do skip 'reason' end # good it 'does something', pending: 'reason' do end # good it 'does something', skip: 'reason' do end ---- [#references-rspecpendingwithoutreason] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PendingWithoutReason [#rspecpredicatematcher] == RSpec/PredicateMatcher |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always (Unsafe) | 1.16 | - |=== Prefer using predicate matcher over using predicate method directly. RSpec defines magic matchers for predicate methods. This cop recommends to use the predicate matcher instead of using predicate method directly. [#examples-rspecpredicatematcher] === Examples [#strict_-true_-enforcedstyle_-inflected-_default_-rspecpredicatematcher] ==== Strict: true, EnforcedStyle: inflected (default) [source,ruby] ---- # bad expect(foo.something?).to be_truthy # good expect(foo).to be_something # also good - It checks "true" strictly. expect(foo.something?).to be(true) ---- [#strict_-false_-enforcedstyle_-inflected-rspecpredicatematcher] ==== Strict: false, EnforcedStyle: inflected [source,ruby] ---- # bad expect(foo.something?).to be_truthy expect(foo.something?).to be(true) # good expect(foo).to be_something ---- [#strict_-true_-enforcedstyle_-explicit-rspecpredicatematcher] ==== Strict: true, EnforcedStyle: explicit [source,ruby] ---- # bad expect(foo).to be_something # good - the above code is rewritten to it by this cop expect(foo.something?).to be(true) # bad - no autocorrect expect(foo) .to be_something(<<~TEXT) bar TEXT # good expect(foo.something?(<<~TEXT)).to be(true) bar TEXT ---- [#strict_-false_-enforcedstyle_-explicit-rspecpredicatematcher] ==== Strict: false, EnforcedStyle: explicit [source,ruby] ---- # bad expect(foo).to be_something # good - the above code is rewritten to it by this cop expect(foo.something?).to be_truthy ---- [#configurable-attributes-rspecpredicatematcher] === Configurable attributes |=== | Name | Default value | Configurable values | Strict | `true` | Boolean | EnforcedStyle | `inflected` | `inflected`, `explicit` | AllowedExplicitMatchers | `[]` | Array |=== [#references-rspecpredicatematcher] === References * https://rspec.rubystyle.guide/#predicate-matchers * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PredicateMatcher [#rspecreceivecounts] == RSpec/ReceiveCounts |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.26 | - |=== Check for `once` and `twice` receive counts matchers usage. [#examples-rspecreceivecounts] === Examples [source,ruby] ---- # bad expect(foo).to receive(:bar).exactly(1).times expect(foo).to receive(:bar).exactly(2).times expect(foo).to receive(:bar).at_least(1).times expect(foo).to receive(:bar).at_least(2).times expect(foo).to receive(:bar).at_most(1).times expect(foo).to receive(:bar).at_most(2).times # good expect(foo).to receive(:bar).once expect(foo).to receive(:bar).twice expect(foo).to receive(:bar).at_least(:once) expect(foo).to receive(:bar).at_least(:twice) expect(foo).to receive(:bar).at_most(:once) expect(foo).to receive(:bar).at_most(:twice).times ---- [#references-rspecreceivecounts] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts [#rspecreceivemessages] == RSpec/ReceiveMessages |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always (Unsafe) | 2.23 | - |=== Prefer `receive_messages` over multiple `receive`s on the same object. [#safety-rspecreceivemessages] === Safety The autocorrection is marked as unsafe, because it may change the order of stubs. This in turn may cause e.g. variables to be called before they are defined. [#examples-rspecreceivemessages] === Examples [source,ruby] ---- # bad before do allow(Service).to receive(:foo).and_return(bar) allow(Service).to receive(:baz).and_return(qux) end # good before do allow(Service).to receive_messages(foo: bar, baz: qux) end # good - ignore same message before do allow(Service).to receive(:foo).and_return(bar) allow(Service).to receive(:foo).and_return(qux) end ---- [#references-rspecreceivemessages] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveMessages [#rspecreceivenever] == RSpec/ReceiveNever |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.28 | - |=== Prefer `not_to receive(...)` over `receive(...).never`. This cop only flags usage with `expect`. It ignores `allow` because `allow(...).to receive(...).never` is a valid way to ensure a method is not called, while `allow(...).not_to receive(...)` would have different semantics. [#examples-rspecreceivenever] === Examples [source,ruby] ---- # bad expect(foo).to receive(:bar).never # good expect(foo).not_to receive(:bar) # not flagged by this cop allow(foo).to receive(:bar).never ---- [#references-rspecreceivenever] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever [#rspecredundantaround] == RSpec/RedundantAround |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.19 | - |=== Remove redundant `around` hook. [#examples-rspecredundantaround] === Examples [source,ruby] ---- # bad around do |example| example.run end # good ---- [#references-rspecredundantaround] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround [#rspecredundantpredicatematcher] == RSpec/RedundantPredicateMatcher |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.26 | - |=== Checks for redundant predicate matcher. [#examples-rspecredundantpredicatematcher] === Examples [source,ruby] ---- # bad expect(foo).to be_exist(bar) expect(foo).not_to be_include(bar) expect(foo).to be_all(bar) # good expect(foo).to exist(bar) expect(foo).not_to include(bar) expect(foo).to all be(bar) ---- [#references-rspecredundantpredicatematcher] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher [#rspecremoveconst] == RSpec/RemoveConst |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.26 | - |=== Checks that `remove_const` is not used in specs. [#examples-rspecremoveconst] === Examples [source,ruby] ---- # bad it 'does something' do Object.send(:remove_const, :SomeConstant) end before do SomeClass.send(:remove_const, :SomeConstant) end ---- [#references-rspecremoveconst] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst [#rspecrepeateddescription] == RSpec/RepeatedDescription |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.9 | - |=== Check for repeated description strings in example groups. [#examples-rspecrepeateddescription] === Examples [source,ruby] ---- # bad RSpec.describe User do it 'is valid' do # ... end it 'is valid' do # ... end end # good RSpec.describe User do it 'is valid when first and last name are present' do # ... end it 'is valid when last name only is present' do # ... end end # good RSpec.describe User do it 'is valid' do # ... end it 'is valid', :flag do # ... end end ---- [#references-rspecrepeateddescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedDescription [#rspecrepeatedexample] == RSpec/RepeatedExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.10 | - |=== Check for repeated examples within example groups. [#examples-rspecrepeatedexample] === Examples [source,ruby] ---- it 'is valid' do expect(user).to be_valid end it 'validates the user' do expect(user).to be_valid end ---- [#references-rspecrepeatedexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExample [#rspecrepeatedexamplegroupbody] == RSpec/RepeatedExampleGroupBody |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.38 | - |=== Check for repeated describe and context block body. [#examples-rspecrepeatedexamplegroupbody] === Examples [source,ruby] ---- # bad describe 'cool feature x' do it { cool_predicate } end describe 'cool feature y' do it { cool_predicate } end # good describe 'cool feature' do it { cool_predicate } end describe 'another cool feature' do it { another_predicate } end # good context 'when case x', :tag do it { cool_predicate } end context 'when case y' do it { cool_predicate } end # good context Array do it { is_expected.to respond_to :each } end context Hash do it { is_expected.to respond_to :each } end ---- [#references-rspecrepeatedexamplegroupbody] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupBody [#rspecrepeatedexamplegroupdescription] == RSpec/RepeatedExampleGroupDescription |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.38 | - |=== Check for repeated example group descriptions. [#examples-rspecrepeatedexamplegroupdescription] === Examples [source,ruby] ---- # bad describe 'cool feature' do # example group end describe 'cool feature' do # example group end # bad context 'when case x' do # example group end describe 'when case x' do # example group end # good describe 'cool feature' do # example group end describe 'another cool feature' do # example group end # good context 'when case x' do # example group end context 'when another case' do # example group end ---- [#references-rspecrepeatedexamplegroupdescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupDescription [#rspecrepeatedincludeexample] == RSpec/RepeatedIncludeExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.44 | - |=== Check for repeated include of shared examples. [#examples-rspecrepeatedincludeexample] === Examples [source,ruby] ---- # bad describe 'foo' do include_examples 'cool stuff' include_examples 'cool stuff' end # bad describe 'foo' do it_behaves_like 'a cool', 'thing' it_behaves_like 'a cool', 'thing' end # bad context 'foo' do it_should_behave_like 'a duck' it_should_behave_like 'a duck' end # good describe 'foo' do include_examples 'cool stuff' end describe 'bar' do include_examples 'cool stuff' end # good describe 'foo' do it_behaves_like 'a cool', 'thing' it_behaves_like 'a cool', 'person' end # good context 'foo' do it_should_behave_like 'a duck' it_should_behave_like 'a goose' end ---- [#references-rspecrepeatedincludeexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample [#rspecrepeatedsubjectcall] == RSpec/RepeatedSubjectCall |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.27 | - |=== Checks for repeated calls to subject missing that it is memoized. [#examples-rspecrepeatedsubjectcall] === Examples [source,ruby] ---- # bad it do subject expect { subject }.to not_change { A.count } end it do expect { subject }.to change { A.count } expect { subject }.to not_change { A.count } end # good it do expect { my_method }.to change { A.count } expect { my_method }.to not_change { A.count } end # also good it do expect { subject.a }.to change { A.count } expect { subject.b }.to not_change { A.count } end ---- [#references-rspecrepeatedsubjectcall] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedSubjectCall [#rspecreturnfromstub] == RSpec/ReturnFromStub |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.16 | 1.22 |=== Checks for consistent style of stub's return setting. Enforces either `and_return` or block-style return in the cases where the returned value is constant. Ignores dynamic returned values are the result would be different This cop can be configured using the `EnforcedStyle` option [#examples-rspecreturnfromstub] === Examples [#_enforcedstyle_-and_return_-_default_-rspecreturnfromstub] ==== `EnforcedStyle: and_return` (default) [source,ruby] ---- # bad allow(Foo).to receive(:bar) { "baz" } expect(Foo).to receive(:bar) { "baz" } # good allow(Foo).to receive(:bar).and_return("baz") expect(Foo).to receive(:bar).and_return("baz") # also good as the returned value is dynamic allow(Foo).to receive(:bar) { bar.baz } ---- [#_enforcedstyle_-block_-rspecreturnfromstub] ==== `EnforcedStyle: block` [source,ruby] ---- # bad allow(Foo).to receive(:bar).and_return("baz") expect(Foo).to receive(:bar).and_return("baz") # good allow(Foo).to receive(:bar) { "baz" } expect(Foo).to receive(:bar) { "baz" } # also good as the returned value is dynamic allow(Foo).to receive(:bar).and_return(bar.baz) ---- [#configurable-attributes-rspecreturnfromstub] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `and_return` | `and_return`, `block` |=== [#references-rspecreturnfromstub] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReturnFromStub [#rspecscatteredlet] == RSpec/ScatteredLet |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 1.14 | 2.31 |=== Checks for let scattered across the example group. Group lets together [#examples-rspecscatteredlet] === Examples [source,ruby] ---- # bad describe Foo do let(:foo) { 1 } subject { Foo } let(:bar) { 2 } before { prepare } let!(:baz) { 3 } end # good describe Foo do subject { Foo } before { prepare } let(:foo) { 1 } let(:bar) { 2 } let!(:baz) { 3 } end ---- [#references-rspecscatteredlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredLet [#rspecscatteredsetup] == RSpec/ScatteredSetup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Command-line only | 1.10 | 2.31 |=== Checks for setup scattered across multiple hooks in an example group. Unify `before` and `after` hooks when possible. However, `around` hooks are allowed to be defined multiple times, as unifying them would typically make the code harder to read. Hooks defined in class methods are also ignored. [#examples-rspecscatteredsetup] === Examples [source,ruby] ---- # bad describe Foo do before { setup1 } before { setup2 } end # good describe Foo do before do setup1 setup2 end end # good describe Foo do around { |example| before1; example.call; after1 } around { |example| before2; example.call; after2 } end # good describe Foo do before { setup1 } def self.setup before { setup2 } end end ---- [#references-rspecscatteredsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredSetup [#rspecsharedcontext] == RSpec/SharedContext |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.13 | - |=== Checks for proper shared_context and shared_examples usage. If there are no examples defined, use shared_context. If there is no setup defined, use shared_examples. [#examples-rspecsharedcontext] === Examples [source,ruby] ---- # bad RSpec.shared_context 'only examples here' do it 'does x' do end it 'does y' do end end # good RSpec.shared_examples 'only examples here' do it 'does x' do end it 'does y' do end end ---- [source,ruby] ---- # bad RSpec.shared_examples 'only setup here' do subject(:foo) { :bar } let(:baz) { :bazz } before do something end end # good RSpec.shared_context 'only setup here' do subject(:foo) { :bar } let(:baz) { :bazz } before do something end end ---- [#references-rspecsharedcontext] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext [#rspecsharedexamples] == RSpec/SharedExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.25 | 2.26 |=== Checks for consistent style for shared example names. Enforces either `string` or `symbol` for shared example names. This cop can be configured using the `EnforcedStyle` option [#examples-rspecsharedexamples] === Examples [#_enforcedstyle_-string_-_default_-rspecsharedexamples] ==== `EnforcedStyle: string` (default) [source,ruby] ---- # bad it_behaves_like :foo_bar_baz it_should_behave_like :foo_bar_baz shared_examples :foo_bar_baz shared_examples_for :foo_bar_baz include_examples :foo_bar_baz # good it_behaves_like 'foo bar baz' it_should_behave_like 'foo bar baz' shared_examples 'foo bar baz' shared_examples_for 'foo bar baz' include_examples 'foo bar baz' ---- [#_enforcedstyle_-symbol_-rspecsharedexamples] ==== `EnforcedStyle: symbol` [source,ruby] ---- # bad it_behaves_like 'foo bar baz' it_should_behave_like 'foo bar baz' shared_examples 'foo bar baz' shared_examples_for 'foo bar baz' include_examples 'foo bar baz' # good it_behaves_like :foo_bar_baz it_should_behave_like :foo_bar_baz shared_examples :foo_bar_baz shared_examples_for :foo_bar_baz include_examples :foo_bar_baz ---- [#configurable-attributes-rspecsharedexamples] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `string` | `string`, `symbol` |=== [#references-rspecsharedexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples [#rspecsingleargumentmessagechain] == RSpec/SingleArgumentMessageChain |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.9 | 1.10 |=== Checks that chains of messages contain more than one element. [#examples-rspecsingleargumentmessagechain] === Examples [source,ruby] ---- # bad allow(foo).to receive_message_chain(:bar).and_return(42) # good allow(foo).to receive(:bar).and_return(42) # also good allow(foo).to receive(:bar, :baz) allow(foo).to receive("bar.baz") ---- [#references-rspecsingleargumentmessagechain] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain [#rspecskipblockinsideexample] == RSpec/SkipBlockInsideExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.19 | - |=== Checks for passing a block to `skip` within examples. [#examples-rspecskipblockinsideexample] === Examples [source,ruby] ---- # bad it 'does something' do skip 'not yet implemented' do do_something end end # good it 'does something' do skip 'not yet implemented' do_something end # good - when outside example skip 'not yet implemented' do end ---- [#references-rspecskipblockinsideexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SkipBlockInsideExample [#rspecsortmetadata] == RSpec/SortMetadata |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 2.14 | - |=== Sort RSpec metadata alphabetically. Only the trailing metadata is sorted. [#examples-rspecsortmetadata] === Examples [source,ruby] ---- # bad describe 'Something', :b, :a context 'Something', foo: 'bar', baz: true it 'works', :b, :a, foo: 'bar', baz: true # good describe 'Something', :a, :b context 'Something', baz: true, foo: 'bar' it 'works', :a, :b, baz: true, foo: 'bar' # good, trailing metadata is sorted describe 'Something', 'description', :a, :b, :z context 'Something', :z, variable, :a, :b ---- [#references-rspecsortmetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata [#rspecspecfilepathformat] == RSpec/SpecFilePathFormat |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.24 | 3.8 |=== Checks that spec file paths are consistent and well-formed. [#examples-rspecspecfilepathformat] === Examples [source,ruby] ---- # bad whatever_spec.rb # describe MyClass my_class_spec.rb # describe MyClass, '#method' # good my_class_spec.rb # describe MyClass my_class_method_spec.rb # describe MyClass, '#method' my_class/method_spec.rb # describe MyClass, '#method' ---- [#_customtransform_-_rubocop__rubocop_-rspec__rspec__-_default_-rspecspecfilepathformat] ==== `CustomTransform: {RuboCop=>rubocop, RSpec=>rspec}` (default) [source,ruby] ---- # good rubocop_spec.rb # describe RuboCop rspec_spec.rb # describe RSpec ---- [#_ignoremethods_-false_-_default_-rspecspecfilepathformat] ==== `IgnoreMethods: false` (default) [source,ruby] ---- # bad my_class_spec.rb # describe MyClass, '#method' ---- [#_ignoremethods_-true_-rspecspecfilepathformat] ==== `IgnoreMethods: true` [source,ruby] ---- # good my_class_spec.rb # describe MyClass, '#method' ---- [#_ignoremetadata_-_type__routing__-_default_-rspecspecfilepathformat] ==== `IgnoreMetadata: {type=>routing}` (default) [source,ruby] ---- # good whatever_spec.rb # describe MyClass, type: :routing do; end ---- [#_enforcedinflector_-active_support_-rspecspecfilepathformat] ==== `EnforcedInflector: active_support` [source,ruby] ---- # Enable to use ActiveSupport's inflector for custom acronyms # like HTTP, etc. Set to "default" by default. # Configure `InflectorPath` with the path to the inflector file. # The default is ./config/initializers/inflections.rb. ---- [#configurable-attributes-rspecspecfilepathformat] === Configurable attributes |=== | Name | Default value | Configurable values | Include | `+**/*_spec.rb+` | Array | Exclude | `+**/spec/routing/**/*+` | Array | CustomTransform | `{"RuboCop" => "rubocop", "RSpec" => "rspec"}` | | IgnoreMethods | `false` | Boolean | IgnoreMetadata | `{"type" => "routing"}` | | InflectorPath | `./config/initializers/inflections.rb` | String | EnforcedInflector | `default` | `` |=== [#references-rspecspecfilepathformat] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat [#rspecspecfilepathsuffix] == RSpec/SpecFilePathSuffix |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.24 | - |=== Checks that spec file paths suffix are consistent and well-formed. [#examples-rspecspecfilepathsuffix] === Examples [source,ruby] ---- # bad my_class/foo_specorb.rb # describe MyClass spec/models/user.rb # describe User spec/models/user_specxrb # describe User # good my_class_spec.rb # describe MyClass # good - shared examples are allowed spec/models/user.rb # shared_examples_for 'foo' ---- [#configurable-attributes-rspecspecfilepathsuffix] === Configurable attributes |=== | Name | Default value | Configurable values | Include | `+**/*_spec*rb*+`, `+**/spec/**/*+` | Array |=== [#references-rspecspecfilepathsuffix] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix [#rspecstubbedmock] == RSpec/StubbedMock |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.44 | - |=== Checks that message expectations do not have a configured response. [#examples-rspecstubbedmock] === Examples [source,ruby] ---- # bad expect(foo).to receive(:bar).with(42).and_return("hello world") # good (without spies) allow(foo).to receive(:bar).with(42).and_return("hello world") expect(foo).to receive(:bar).with(42) ---- [#references-rspecstubbedmock] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StubbedMock [#rspecsubjectdeclaration] == RSpec/SubjectDeclaration |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.5 | - |=== Ensure that subject is defined using subject helper. [#examples-rspecsubjectdeclaration] === Examples [source,ruby] ---- # bad let(:subject) { foo } let!(:subject) { foo } subject(:subject) { foo } subject!(:subject) { foo } # bad block = -> {} let(:subject, &block) # good subject(:test_subject) { foo } ---- [#references-rspecsubjectdeclaration] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectDeclaration [#rspecsubjectstub] == RSpec/SubjectStub |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.7 | 2.8 |=== Checks for stubbed test subjects. Checks nested subject stubs for innermost subject definition when subject is also defined in parent example groups. [#examples-rspecsubjectstub] === Examples [source,ruby] ---- # bad describe Article do subject(:article) { Article.new } it 'indicates that the author is unknown' do allow(article).to receive(:author).and_return(nil) expect(article.description).to include('by an unknown author') end end # bad describe Article do subject(:foo) { Article.new } context 'nested subject' do subject(:article) { Article.new } it 'indicates that the author is unknown' do allow(article).to receive(:author).and_return(nil) expect(article.description).to include('by an unknown author') end end end # good describe Article do subject(:article) { Article.new(author: nil) } it 'indicates that the author is unknown' do expect(article.description).to include('by an unknown author') end end ---- [#references-rspecsubjectstub] === References * https://rspec.rubystyle.guide/#dont-stub-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectStub * https://robots.thoughtbot.com/don-t-stub-the-system-under-test * https://penelope.zone/2015/12/27/introducing-rspec-smells-and-where-to-find-them.html#smell-1-stubjec [#rspecundescriptiveliteralsdescription] == RSpec/UndescriptiveLiteralsDescription |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 2.29 | - |=== Description should be descriptive. If example group or example contains only `execute string`, numbers and regular expressions, the description is not clear. [#examples-rspecundescriptiveliteralsdescription] === Examples [source,ruby] ---- # bad describe `time` do # ... end # bad context /when foo/ do # ... end # bad it 10000 do # ... end # good describe Foo do # ... end # good describe '#foo' do # ... end # good context "when #{foo} is bar" do # ... end # good it 'does something' do # ... end ---- [#references-rspecundescriptiveliteralsdescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UndescriptiveLiteralsDescription [#rspecunspecifiedexception] == RSpec/UnspecifiedException |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.30 | - |=== Checks for a specified error in checking raised errors. Enforces one of an Exception type, a string, or a regular expression to match against the exception message as a parameter to `raise_error` [#examples-rspecunspecifiedexception] === Examples [source,ruby] ---- # bad expect { raise StandardError.new('error') }.to raise_error # good expect { raise StandardError.new('error') }.to raise_error(StandardError) expect { raise StandardError.new('error') }.to raise_error('error') expect { raise StandardError.new('error') }.to raise_error(/err/) expect { do_something }.not_to raise_error ---- [#references-rspecunspecifiedexception] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UnspecifiedException [#rspecvariabledefinition] == RSpec/VariableDefinition |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.40 | - |=== Checks that memoized helpers names are symbols or strings. [#examples-rspecvariabledefinition] === Examples [#enforcedstyle_-symbols-_default_-rspecvariabledefinition] ==== EnforcedStyle: symbols (default) [source,ruby] ---- # bad subject('user') { create_user } let('user_name') { 'Adam' } # good subject(:user) { create_user } let(:user_name) { 'Adam' } ---- [#enforcedstyle_-strings-rspecvariabledefinition] ==== EnforcedStyle: strings [source,ruby] ---- # bad subject(:user) { create_user } let(:user_name) { 'Adam' } # good subject('user') { create_user } let('user_name') { 'Adam' } ---- [#configurable-attributes-rspecvariabledefinition] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `symbols` | `symbols`, `strings` |=== [#references-rspecvariabledefinition] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableDefinition [#rspecvariablename] == RSpec/VariableName |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.40 | 2.13 |=== Checks that memoized helper names use the configured style. Variables can be excluded from checking using the `AllowedPatterns` option. [#examples-rspecvariablename] === Examples [#enforcedstyle_-snake_case-_default_-rspecvariablename] ==== EnforcedStyle: snake_case (default) [source,ruby] ---- # bad subject(:userName1) { 'Adam' } let(:userName2) { 'Adam' } # good subject(:user_name_1) { 'Adam' } let(:user_name_2) { 'Adam' } ---- [#enforcedstyle_-camelcase-rspecvariablename] ==== EnforcedStyle: camelCase [source,ruby] ---- # bad subject(:user_name_1) { 'Adam' } let(:user_name_2) { 'Adam' } # good subject(:userName1) { 'Adam' } let(:userName2) { 'Adam' } ---- [#allowedpatterns-configuration-rspecvariablename] ==== AllowedPatterns configuration [source,ruby] ---- # rubocop.yml # RSpec/VariableName: # EnforcedStyle: snake_case # AllowedPatterns: # - ^userFood ---- [source,ruby] ---- # okay because it matches the `^userFood` regex in `AllowedPatterns` subject(:userFood_1) { 'spaghetti' } let(:userFood_2) { 'fettuccine' } ---- [#configurable-attributes-rspecvariablename] === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `snake_case` | `snake_case`, `camelCase` | AllowedPatterns | `[]` | Array |=== [#references-rspecvariablename] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName [#rspecverifieddoublereference] == RSpec/VerifiedDoubleReference |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always (Unsafe) | 2.10.0 | 3.4 |=== Checks for consistent verified double reference style. [#safety-rspecverifieddoublereference] === Safety This cop is unsafe because the correction requires loading the class. Loading before stubbing causes RSpec to only allow instance methods to be stubbed. [#examples-rspecverifieddoublereference] === Examples [source,ruby] ---- # bad let(:foo) do instance_double('ClassName', method_name: 'returned_value') end # good let(:foo) do instance_double(ClassName, method_name: 'returned_value') end ---- [#reference-is-any-dynamic-variable_-no-enforcement-rspecverifieddoublereference] ==== Reference is any dynamic variable. No enforcement [source,ruby] ---- # good let(:foo) do instance_double(@klass, method_name: 'returned_value') end ---- [#references-rspecverifieddoublereference] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference * https://rspec.info/features/3-12/rspec-mocks/verifying-doubles [#rspecverifieddoubles] == RSpec/VerifiedDoubles |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.2.1 | 1.5 |=== Prefer using verifying doubles over normal doubles. [#examples-rspecverifieddoubles] === Examples [source,ruby] ---- # bad let(:foo) do double("ClassName", method_name: 'returned value') end # bad let(:foo) do spy("ClassName", method_name: 'returned value') end # good let(:foo) do instance_double("ClassName", method_name: 'returned value') end # good let(:foo) do class_double("ClassName", method_name: 'returned value') end # good let(:foo) do object_double("some object", method_name: 'returned value') end ---- [#_ignorenameless_-true-_default__-rspecverifieddoubles] ==== `IgnoreNameless: true (default)` [source,ruby] ---- # good let(:foo) do double(method_name: 'returned value') end # good let(:foo) do double end ---- [#_ignorenameless_-false_-rspecverifieddoubles] ==== `IgnoreNameless: false` [source,ruby] ---- # bad let(:foo) do double(method_name: 'returned value') end # bad let(:foo) do double end ---- [#_ignoresymbolicnames_-false-_default__-rspecverifieddoubles] ==== `IgnoreSymbolicNames: false (default)` [source,ruby] ---- # bad let(:foo) do double(:foo) end ---- [#_ignoresymbolicnames_-true_-rspecverifieddoubles] ==== `IgnoreSymbolicNames: true` [source,ruby] ---- # good let(:foo) do double(:foo) end ---- [#configurable-attributes-rspecverifieddoubles] === Configurable attributes |=== | Name | Default value | Configurable values | IgnoreNameless | `true` | Boolean | IgnoreSymbolicNames | `false` | Boolean |=== [#references-rspecverifieddoubles] === References * https://rspec.rubystyle.guide/#doubles * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles * https://rspec.info/features/3-12/rspec-mocks/verifying-doubles [#rspecvoidexpect] == RSpec/VoidExpect |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.16 | - |=== Checks void `expect()`. [#examples-rspecvoidexpect] === Examples [source,ruby] ---- # bad expect(something) # good expect(something).to be(1) ---- [#references-rspecvoidexpect] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect [#rspecyield] == RSpec/Yield |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Always | 1.32 | - |=== Checks for calling a block within a stub. [#examples-rspecyield] === Examples [source,ruby] ---- # bad allow(foo).to receive(:bar) { |&block| block.call(1) } # good expect(foo).to receive(:bar).and_yield(1) ---- [#references-rspecyield] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Yield rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/development.adoc000066400000000000000000000066441512756157400261210ustar00rootroot00000000000000= Development This page describes considerations when developing RSpec-specific cops. It is intended to be a complement to the general https://docs.rubocop.org/rubocop/development.html[RuboCop development documentation]. == Create a new cop NOTE: Clone the repository and run `bundle install` if not done yet. The following rake task can only be run inside the rubocop project directory itself. Use the bundled rake task `new_cop` to generate a cop template: [source,sh] ---- $ bundle exec rake 'new_cop[RSpec/CopName]' [create] lib/rubocop/cop/rspec/cop_name.rb [create] spec/rubocop/cop/rspec/cop_name_spec.rb [modify] lib/rubocop/cop/rspec_cops.rb - `require_relative 'rspec/cop_name'` was injected. [modify] A configuration for the cop is added into config/default.yml. Do 4 steps: 1. Modify the description of RSpec/CopName in config/default.yml 2. Implement your new cop in the generated file! 3. Add an entry about new cop to CHANGELOG.md 4. Commit your new cop with a message such as e.g. "Add new `#{badge}` cop" ---- === Choose a Name Use the following rules to give the new cop a name: * Pick a department. See the xref:cops.adoc[list of existing departments] * The name is self-explanatory * The name explains the offense the cop detects, e.g. `ExtraSpacing` * The name starts with a noun instead of a verb, e.g. `ArrayAlignment` instead of `AlignArray` * The name is easy to understand, e.g. `IndentationStyle` instead of just `Tab` * The name is specific, e.g. `DuplicateHashKey` instead of just `DuplicateKey` * The name is neutral when possible and accommodates multiple styles when feasible, e.g. `EmptyLineBeforeBegin`. * The name uses commonly-used terms, e.g. `RedundantPercentI` instead of `RedundantPercentSymbolArray` * The name uses correct terms, e.g. arguments in a method call, and parameters in a method signature * Lines with no symbols are called "empty", not "blank", e.g. `LeadingEmptyLines` instead of `LeadingBlankLines` * Prefer "redundant" to "unneeded", e.g. `RedundantSelf` instead of `UnneededSelf` See the https://github.com/rubocop/rubocop/blob/12fd014e255617a08b7b42aa5df0745e7382af88/config/obsoletion.yml#L4["renamed" section of `config/obsoletion.yml`] for good and bad examples (old name is on the left, new name on the right). == Base class The `RuboCop::Cop::RSpec::Base` class includes convenient https://docs.rubocop.org/rubocop-ast/node_pattern.html[node pattern DSL] matchers that will automatically account for any xref:usage.adoc#rspec-dsl-configuration[custom RSpec DSL configuration]. For example, if the project defines https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md[`let_it_be`] as a `Helper`, then all cops will find `let_it_be` when using the `let?` matcher. == Writing specs When working on RSpec-specific cops, ensure that the https://github.com/rubocop/rubocop-rspec/blob/master/config/default.yml[default language config] is loaded for all RSpec specs. For example: [source,ruby] ---- require 'rubocop/rspec/shared_contexts/default_rspec_language_config_context' RSpec.config do |config| # Set metadata on all cop specs config.define_derived_metadata(file_path: %r{/spec/rubocop/cop/}) do |meta| meta[:type] = :cop_spec end # Include RuboCop's config shared context for all cop specs config.define_derived_metadata(type: :cop_spec) do |meta| meta[:config] = true end config.include_context 'with default RSpec/Language config', :config end ---- rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/index.adoc000066400000000000000000000035211512756157400246750ustar00rootroot00000000000000= RuboCop RSpec https://rspec.info/[RSpec]-specific analysis for your projects, as an extension to https://github.com/rubocop/rubocop[RuboCop]. RuboCop RSpec follows the https://docs.rubocop.org/rubocop/versioning.html[RuboCop versioning guide]. In a nutshell, between major versions new cops are introduced in a special `pending` status. That means that they won't be run unless explicitly told otherwise. RuboCop will warn on start that certain cops are neither explicitly enabled and disabled. On a major version release, all `pending` cops are enabled. == Project Goals * Enforce the guidelines and best practices outlined in the community https://rspec.rubystyle.guide[RSpec style guide] * Simplify the process of adopting new RSpec functionality == Non-goals of RuboCop RSpec === Enforcing `should` vs. `expect` syntax Enforcing [source,ruby] ---- expect(calculator.compute(line_item)).to eq(5) ---- over [source,ruby] ---- calculator.compute(line_item).should == 5 ---- is a feature of RSpec itself - you can read about it in the "Disable should syntax" section of https://rspec.info/features/3-12/rspec-expectations/syntax-configuration[RSpec Documentation]. === Enforcing an explicit RSpec receiver for top-level methods (disabling monkey patching) Enforcing [source,ruby] ---- RSpec.describe MyClass do ... end ---- over [source,ruby] ---- describe MyClass do ... end ---- can be achieved using RSpec's `disable_monkey_patching!` method, which you can read more about in the https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode[RSpec Documentation]. This will also prevent `should` from being defined on every object in your system. Before disabling `should` you will need all your specs to use the `expect` syntax. You can use http://yujinakayama.me/transpec/[Transpec], which will do the conversion for you. rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/installation.adoc000066400000000000000000000003071512756157400262660ustar00rootroot00000000000000= Installation Just install the `rubocop-rspec` gem [source,bash] ---- gem install rubocop-rspec ---- or if you use bundler put this in your `Gemfile` [source,ruby] ---- gem 'rubocop-rspec' ---- rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/third_party_rspec_syntax_extensions.adoc000066400000000000000000000040711512756157400332010ustar00rootroot00000000000000= RSpec syntax extensions in third-party gems Some gems, e.g. https://github.com/CanCanCommunity/cancancan[cancancan], https://github.com/palkan/action_policy[action_policy] and https://github.com/varvet/pundit[pundit] provide their own extensions and aliases to RSpec syntax. Also, RSpec extensions like https://github.com/palkan/test-prof[test-prof], https://github.com/rspec/rspec-its[rspec-its] and https://github.com/zverok/saharspec#its-addons[saharspec] do. By default, RuboCop RSpec is not aware of those syntax extensions, and does not intend to gather all of them in the default configuration file. It is possible for the gems to provide configuration for RuboCop RSpec to allow proper detection of RSpec elements. RuboCop https://docs.rubocop.org/rubocop/configuration.html#inheriting-configuration-from-a-dependency-gem[provides third-party gems with an ability to configure RuboCop]. == Packaging configuration for RuboCop RSpec NOTE: Due to https://github.com/rubocop/rubocop-rspec/issues/1126[a bug], this feature doesn't work properly for `rubocop-rspec` 2.5.0 and earlier versions. For a third-party gem, it's sufficient to follow three steps: 1. Provide a configuration file (e.g. `.rubocop_rspec_alias_config.yml` or `config/rubocop-rspec.yml`). Please check with the xref:usage.adoc#rspec-dsl-configuration[RSpec DSL configuration] how different elements of RSpec syntax can be configured. 2. Add a section to their documentation how users can benefit from using RuboCop RSpec with full detection of their syntax extensions. Example: ## Usage with RuboCop RSpec Please add the following to your `.rubocop.yml` to make RuboCop RSpec aware of our cool syntax extensions: inherit_gem: third-party-gem: .rubocop_rspec_alias_config.yml 3. Include the configuration file to their package by updating their `gemspec`'s `spec.files` to include the aforementioned configuration file. See pull requests: https://github.com/test-prof/test-prof/pull/199[test-prof], and https://github.com/palkan/action_policy/pull/138[action_policy] for a less trivial example. rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/upgrade_to_version_2.adoc000066400000000000000000000174411512756157400277130ustar00rootroot00000000000000= Upgrade to Version 2.x :doctype: book == Configuration File Update In version 2.x: - `RSpec/InvalidPredicateMatcher` cop is removed - `CustomIncludeMethods` configuration option for `RSpec/EmptyExampleGroup` is removed - cop departments are nested for cops with a department that doesn't match the extension name (`Capybara`, `FactoryBot`, `Rails`) - `AllCops/RSpec/Patterns`/`AllCops/FactoryBot/Patterns` options are removed - Calling `super` from `#on_new_investigation` defined in a cop is mandatory now - In specs, do not define `cop` [discrete] === Adjust the configuration of `RSpec/EmptyExampleGroup` [source,yaml] ---- # .rubocop.yml # Before RSpec/EmptyExampleGroup: CustomIncludeMethods: - include_tests # After RSpec: Language: Includes: Examples: - include_tests ---- === Add a top-level `RSpec` department RuboCop extensions had cops with clashing names and departments, e.g. both `rspec-rails` and `rubocop-rspec` had `Rails::HttpStatus` cops. To avoid issues, e.g. inability to disable just one of the cops, each extension now has its own uber-department. Expectedly, RuboCop RSpec's uber-department name is `RSpec`. Changes are only applied to cops that don't already have the department set to `RSpec`, i.e. `Capybara`, `FactoryBot` and `Rails`. [source,yaml] ---- # .rubocop.yml # Before Capybara/CurrentPathExpectation: Enabled: false FactoryBot/AttributeDefinedStatically: Enabled: false # remains the same RSpec/EmptyExampleGroup: Enabled: false # After RSpec/Capybara/CurrentPathExpectation: Enabled: false RSpec/FactoryBot/AttributeDefinedStatically: Enabled: false # remains the same RSpec/EmptyExampleGroup: Enabled: false ---- https://github.com/rubocop/rubocop/pull/8490[Learn more about this change]. === Use the RuboCop standard `Include` option to filter inspected files `Patterns` was a RuboCop RSpec-specific option, and RuboCop has a standard replacement. [source,yaml] ---- # .rubocop.yml # Before AllCops: RSpec/FactoryBot: Patterns: - spec/factories/**/*.rb - property/factories/**/*.rb # After RSpec/FactoryBot: Include: - spec/factories/**/*.rb - property/factories/**/*.rb ---- NOTE: Please keep in mind that merge mode for `Include` is set to override the default settings, so if you intend to add a path while keeping the default paths, you should include the default `Include` paths in your configuration. https://github.com/rubocop/rubocop-rspec/pull/1063[Learn more about this change]. == Custom Cop Update Guide Due to significant API changes, custom cops may break. Here is the summary of the changes: 1. The base class for cops is now `RuboCop::Cop::RSpec::Base` instead of `RuboCop::Cop::RSpec::Cop`. 2. The module `RuboCop::Cop::RSpec::TopLevelDescribe` is replaced with a more generic `RuboCop::Cop::RSpec::TopLevelGroup`. 3. `RuboCop::RSpec::Language` has been completely rewritten to support dynamic RSpec DSL aliases and negated matchers to fully support third-party libraries such as RSpec Rails, Pundit, Action Policy and many others. 4. RuboCop RSpec updated the dependency of RuboCop to 1.0+. Below are the necessary steps to update custom cops to work with `rubocop-rspec` version 2.x. === Change the Parent Class Change the parent class of the custom cops from `RuboCop::Cop::RSpec::Cop` to `RuboCop::Cop::RSpec::Base`. [source,ruby] ---- # Before module RuboCop module Cop module RSpec class FightPowerty < Cop # After module RuboCop module Cop module RSpec class FightPowerty < Base ---- https://github.com/rubocop/rubocop-rspec/pull/962[Example pull request]. === Replace `TopLevelDescribe` `TopLevelDescribe` was incomplete, had poor performance and did not distinguish between example groups and shared example groups. `TopLevelGroup` provides a similar interface, but instead of a single `on_top_level_describe` hook there are two, `on_top_level_example_group` and `on_top_level_group`. There's no need yet for `on_top_level_shared_group` for RuboCop core cops, but if your custom cop needs such a hook, please feel free to send a pull request. Additionally, `single_top_level_describe?` is removed with no direct replacement. You may use `top_level_groups` query method instead, e.g. `top_level_groups.one?`. Example pull requests to replace `TopLevelDescribe` with `TopLevelGroup` [https://github.com/rubocop/rubocop-rspec/pull/978[1], https://github.com/rubocop/rubocop-rspec/pull/932[2], https://github.com/rubocop/rubocop-rspec/pull/977[3]]. === Change the `Language` Module Usages To allow for lazy initialization, and for loading of the language configuration after the class are loaded, a https://docs.rubocop.org/rubocop-ast/node_pattern.html#to-call-functions[function call feature of RuboCop AST] is used. The `RuboCop::RSpec::Language` is completely different now. `Hooks::ALL` and alike, and their accompanying helpers work differently. [source,ruby] ---- # Before def_node_matcher :shared_context, SharedGroups::CONTEXT.block_pattern # After def_node_matcher :shared_context, '(block (send #rspec? #SharedGroups.context ...) ...)' ---- [source,ruby] ---- # Before def_node_search :examples?, (Includes::EXAMPLES + Examples::ALL).send_pattern # After def_node_search :examples?, '(send nil? {#Includes.examples #Examples.all} ...)' ---- [source,ruby] ---- # Before def_node_search :find_rspec_blocks, ExampleGroups::ALL.block_pattern # After def_node_search :find_rspec_blocks, '(block (send #rspec? #ExampleGroups.all ...) ...)' ---- If you were calling Language elements directly, you have to make the same adjustments: [source,ruby] ---- # Before node&.sym_type? && Hooks::Scopes::ALL.include?(node.value) # After node&.sym_type? && Language::HookScopes.all(node.value) ---- You may see a common pattern in the change. There is a small exception, though: [source,ruby] ---- # Before ExampleGroups::GROUPS # After ExampleGroups.regular # Before Examples::EXAMPLES # After Examples.regular ---- https://github.com/rubocop/rubocop-rspec/pull/956[Pull request with more examples]. === Always call `super` from `on_new_investigation` in your cops `on_new_investigation` is now used for internal purposes, and not calling `super` from your cop involves a risk of configuration not being properly loaded, and dynamic RSpec DSL matchers won't work. NOTE: You don't have to define `on_new_investigation` in your cops unless you need to. [source,ruby] ---- module RuboCop module Cop module RSpec class MultipleMemoizedHelpers < Base def on_new_investigation super # Always call `super` @example_group_memoized_helpers = {} end end end end end ---- https://github.com/rubocop/rubocop-rspec/pull/956[Pull request with more examples]. === Use `:config` RSpec metadata in cop specs `:config` metadata should be added to the top-level example group of your cop spec. Doing otherwise will not pass configuration to the cop, and dynamic RSpec DSL matchers might not work. [source,ruby] ---- # Before RSpec.describe 'MyMightyCop' do let(:cop) { described_class.new } # ... end # After RSpec.describe 'MyMightyCop', :config do # `cop` is defined for you by RuboCop's shared context that is included # to example groups with :config metadata # ... end ---- https://github.com/rubocop/rubocop/blob/51ff1d7e29c985732fe129082c98d66c531a2611/lib/rubocop/rspec/shared_contexts.rb#L56[RuboCop takes care of defining everything for your cop specs]. === Conform with RuboCop API Changes The parent project, RuboCop, has API changes. While they won't result in cop breakages, it is recommended to update cops to use new API's. Follow the https://docs.rubocop.org/rubocop/v1_upgrade_notes[RuboCop v1 update guide] to adjust custom cops' use of RuboCop's auto-correction API. rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/upgrade_to_version_3.adoc000066400000000000000000000030001512756157400276760ustar00rootroot00000000000000= Upgrade to Version 3.x :doctype: book == Configuration File Update In version 3.x: - cop departments are extracted to another gem. (`Capybara`, `FactoryBot`, `Rails`) [discrete] === Extraction of cop departments. (`Capybara`, `FactoryBot`, `Rails`) If you are using the RSpec/Capybara, RSpec/FactoryBot, or RSpec/Rails departments -- or have one in a `require` list in your rubocop.yml -- you need to install the corresponding gem and add it to your `.rubocop.yml` file: * Capybara: `rubocop-capybara` * FactoryBot: `rubocop-factory_bot` * Rails: `rubocop-rspec_rails` For example, if you are using the RSpec/Capybara department, you need to install the `rubocop-capybara` gem and add it to your `.rubocop.yml` file: [source,ruby] ---- # Gemfile group :test do gem 'rubocop-rspec' gem 'rubocop-capybara' end ---- [source,yaml] ---- require: - rubocop-rspec - rubocop-capybara ---- And you need to remove the old department in your `.rubocop.yml` file: [source,yaml] ---- RSpec/Capybara: Enabled: false ---- For another example, if you are not using these departments, you don't need to do anything. And when you update to RuboCop RSpec v3.0.0, you need to remove the old departments from your `.rubocop.yml` file, e.g.: [source,yaml] ---- RSpec/Capybara: Enabled: false RSpec/FactoryBot: Enabled: false RSpec/Rails: Enabled: false ---- == Troubleshooting If you're seeing `cannot load such file` when running rubocop, even after installing the gems, restart the server with `rubocop --restart-server`. rubocop-rubocop-rspec-a5aeb29/docs/modules/ROOT/pages/usage.adoc000066400000000000000000000057621512756157400247030ustar00rootroot00000000000000= Usage You need to tell RuboCop to load the RSpec extension. There are three ways to do this: == RuboCop configuration file Put this into your `.rubocop.yml`: ---- plugins: rubocop-rspec ---- or, if you are using several extensions: ---- plugins: - rubocop-rspec - rubocop-performance ---- Now you can run `rubocop` and it will automatically load the RuboCop RSpec cops together with the standard cops. NOTE: The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`. === RSpec DSL configuration In case you https://github.com/rspec/rspec-core/blob/b0d0843a285693c64cdbe0c85726db155b46047e/lib/rspec/core/configuration.rb#L1122[define aliases for RSpec DSL], i.e. examples, example groups, hooks, or include example statements, you need to configure it so those elements are properly detected by RuboCop RSpec. [source,ruby] ---- # spec/spec_helper.rb RSpec.configure do |c| c.alias_example_group_to :detail, :detailed => true end # spec/detail_spec.rb RSpec.detail "a detail" do it "can do some less important stuff" do end end ---- [source,yaml] ---- # .rubocop.yml RSpec: Language: ExampleGroups: Regular: - detail ---- Some libraries extensively define RSpec DSL aliases (e.g. Pundit, Action Policy) or augment existing elements providing the same semantics (e.g. `let_it_be` from `test-prof`). Those libraries can provide necessary configuration, but won't necessarily do so. If they do, their README will mention that you have to explicitly require their configuration from your `.rubocop.yml` file. [source,yaml] ---- # .rubocop.yml require: - rubocop-rspec - test-prof # or RSpec: Language: Helpers: - let_it_be ---- NOTE: the default merge mode is to inherit, so you won't remove any of the default settings. RuboCop RSpec's https://github.com/rubocop/rubocop-rspec/blob/a43424527c09fae2e6ddb133f4b2988f6c46bb2e/config/default.yml#L6[default configuration] is a good source of information on what can be configured. == Command line [source,bash] ---- $ rubocop --plugin rubocop-rspec ---- == Rake task [source,ruby] ---- RuboCop::RakeTask.new do |task| task.plugins << 'rubocop-rspec' end ---- == Code Climate `rubocop-rspec` is available on Code Climate as part of the rubocop engine. https://codeclimate.com/changelog/55a433bbe30ba00852000fac[Learn More]. == Inspecting files that don't end with `_spec.rb` By default, `rubocop-rspec` only inspects code within paths ending in `_spec.rb` or including `spec/`. You can override this setting in your config file by setting `Include`: [source,yaml] ---- # Inspect files in `test/` directory RSpec: Include: - '**/test/**/*' ---- [source,yaml] ---- # Inspect only files ending with `_test.rb` RSpec: Include: - '**/*_test.rb' ---- NOTE: Please keep in mind that merge mode for `Include` is set to override the default settings, so if you intend to add a path while keeping the default paths, you should include the default `Include` paths in your configuration. rubocop-rubocop-rspec-a5aeb29/lib/000077500000000000000000000000001512756157400172215ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/lib/rubocop-rspec.rb000066400000000000000000000033561512756157400223400ustar00rootroot00000000000000# frozen_string_literal: true require 'pathname' require 'yaml' require 'rubocop' require_relative 'rubocop/rspec' require_relative 'rubocop/rspec/language' require_relative 'rubocop/rspec/node' require_relative 'rubocop/rspec/plugin' require_relative 'rubocop/rspec/version' require_relative 'rubocop/rspec/wording' require_relative 'rubocop/cop/rspec/mixin/file_help' require_relative 'rubocop/cop/rspec/mixin/final_end_location' require_relative 'rubocop/cop/rspec/mixin/inside_example_group' require_relative 'rubocop/cop/rspec/mixin/location_help' require_relative 'rubocop/cop/rspec/mixin/metadata' require_relative 'rubocop/cop/rspec/mixin/namespace' require_relative 'rubocop/cop/rspec/mixin/skip_or_pending' require_relative 'rubocop/cop/rspec/mixin/top_level_group' require_relative 'rubocop/cop/rspec/mixin/variable' # Dependent on `RuboCop::Cop::RSpec::FinalEndLocation`. require_relative 'rubocop/cop/rspec/mixin/comments_help' require_relative 'rubocop/cop/rspec/mixin/empty_line_separation' require_relative 'rubocop/cop/rspec/base' require_relative 'rubocop/rspec/align_let_brace' require_relative 'rubocop/rspec/concept' require_relative 'rubocop/rspec/corrector/move_node' require_relative 'rubocop/rspec/example' require_relative 'rubocop/rspec/example_group' require_relative 'rubocop/rspec/hook' require_relative 'rubocop/cop/rspec_cops' # We have to register our autocorrect incompatibilities in RuboCop's cops # as well so we do not hit infinite loops RuboCop::Cop::Layout::ExtraSpacing.singleton_class.prepend( Module.new do def autocorrect_incompatible_with super.push(RuboCop::Cop::RSpec::AlignLeftLetBrace) .push(RuboCop::Cop::RSpec::AlignRightLetBrace) end end ) RuboCop::AST::Node.include(RuboCop::RSpec::Node) rubocop-rubocop-rspec-a5aeb29/lib/rubocop/000077500000000000000000000000001512756157400206725ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/000077500000000000000000000000001512756157400214535ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/000077500000000000000000000000001512756157400225675ustar00rootroot00000000000000rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/align_left_let_brace.rb000066400000000000000000000021461512756157400272230ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that left braces for adjacent single line lets are aligned. # # @example # # bad # let(:foobar) { blahblah } # let(:baz) { bar } # let(:a) { b } # # # good # let(:foobar) { blahblah } # let(:baz) { bar } # let(:a) { b } # class AlignLeftLetBrace < Base extend AutoCorrector MSG = 'Align left let brace' def self.autocorrect_incompatible_with [Layout::ExtraSpacing] end def on_new_investigation super return if processed_source.blank? token_aligner.offending_tokens.each do |let| add_offense(let.loc.begin) do |corrector| corrector.insert_before( let.loc.begin, token_aligner.indent_for(let) ) end end end private def token_aligner RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/align_right_let_brace.rb000066400000000000000000000021671512756157400274110ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that right braces for adjacent single line lets are aligned. # # @example # # bad # let(:foobar) { blahblah } # let(:baz) { bar } # let(:a) { b } # # # good # let(:foobar) { blahblah } # let(:baz) { bar } # let(:a) { b } # class AlignRightLetBrace < Base extend AutoCorrector MSG = 'Align right let brace' def self.autocorrect_incompatible_with [Layout::ExtraSpacing] end def on_new_investigation super return if processed_source.blank? token_aligner.offending_tokens.each do |let| add_offense(let.loc.end) do |corrector| corrector.insert_before( let.loc.end, token_aligner.indent_for(let) ) end end end private def token_aligner RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/any_instance.rb000066400000000000000000000020121512756157400255620ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that instances are not being stubbed globally. # # Prefer instance doubles over stubbing any instance of a class # # @example # # bad # describe MyClass do # before { allow_any_instance_of(MyClass).to receive(:foo) } # end # # # good # describe MyClass do # let(:my_instance) { instance_double(MyClass) } # # before do # allow(MyClass).to receive(:new).and_return(my_instance) # allow(my_instance).to receive(:foo) # end # end # class AnyInstance < Base MSG = 'Avoid stubbing using `%s`.' RESTRICT_ON_SEND = %i[ any_instance allow_any_instance_of expect_any_instance_of ].freeze def on_send(node) add_offense(node, message: format(MSG, method: node.method_name)) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/around_block.rb000066400000000000000000000044651512756157400255670ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that around blocks actually run the test. # # @example # # bad # around do # some_method # end # # around do |test| # some_method # end # # # good # around do |test| # some_method # test.call # end # # around do |test| # some_method # test.run # end # class AroundBlock < Base MSG_NO_ARG = 'Test object should be passed to around block.' MSG_UNUSED_ARG = 'You should call `%s.call` ' \ 'or `%s.run`.' # @!method hook_block(node) def_node_matcher :hook_block, <<~PATTERN (block (send nil? :around sym ?) (args $...) ...) PATTERN # @!method hook_numblock(node) def_node_matcher :hook_numblock, <<~PATTERN (numblock (send nil? :around sym ?) ...) PATTERN # @!method find_arg_usage(node) def_node_search :find_arg_usage, <<~PATTERN {(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)} PATTERN def on_block(node) hook_block(node) do |(example_proxy)| if example_proxy.nil? add_no_arg_offense(node) else check_for_unused_proxy(node, example_proxy) end end end def on_numblock(node) hook_numblock(node) do check_for_numblock(node) end end private def add_no_arg_offense(node) add_offense(node, message: MSG_NO_ARG) end def check_for_unused_proxy(block, proxy) find_arg_usage(block) do |usage| return if usage.include?(s(:lvar, proxy.name)) end add_offense( proxy, message: format(MSG_UNUSED_ARG, arg: proxy.name) ) end def check_for_numblock(block) find_arg_usage(block) do |usage| return if usage.include?(s(:lvar, :_1)) end add_offense( block.children.last, message: format(MSG_UNUSED_ARG, arg: :_1) ) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/base.rb000066400000000000000000000013421512756157400240260ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # @abstract parent class to RSpec cops class Base < ::RuboCop::Cop::Base include RuboCop::RSpec::Language exclude_from_registry # Invoke the original inherited hook so our cops are recognized def self.inherited(subclass) # rubocop:disable Lint/MissingSuper RuboCop::Cop::Base.inherited(subclass) end # Set the config for dynamic DSL configuration-aware helpers # that have no other means of accessing the configuration. def on_new_investigation super RuboCop::RSpec::Language.config = config['RSpec']['Language'] end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/be.rb000066400000000000000000000020121512756157400234750ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check for expectations where `be` is used without argument. # # The `be` matcher is too generic, as it pass on everything that is not # nil or false. If that is the exact intend, use `be_truthy`. In all other # cases it's better to specify what exactly is the expected value. # # @example # # bad # expect(foo).to be # # # good # expect(foo).to be_truthy # expect(foo).to be 1.0 # expect(foo).to be(true) # class Be < Base MSG = "Don't use `be` without an argument." RESTRICT_ON_SEND = Runners.all # @!method be_without_args(node) def_node_matcher :be_without_args, <<~PATTERN (send _ #Runners.all $(send nil? :be)) PATTERN def on_send(node) be_without_args(node) do |matcher| add_offense(matcher.loc.selector) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/be_empty.rb000066400000000000000000000021501512756157400247160ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Prefer using `be_empty` when checking for an empty array. # # @example # # bad # expect(array).to contain_exactly # expect(array).to match_array([]) # # # good # expect(array).to be_empty # class BeEmpty < Base extend AutoCorrector MSG = 'Use `be_empty` matchers for checking an empty array.' RESTRICT_ON_SEND = %i[contain_exactly match_array].freeze # @!method expect_array_matcher?(node) def_node_matcher :expect_array_matcher?, <<~PATTERN (send (send nil? :expect _) #Runners.all ${ (send nil? :match_array (array)) (send nil? :contain_exactly) } _? ) PATTERN def on_send(node) expect_array_matcher?(node.parent) do |expect| add_offense(expect) do |corrector| corrector.replace(expect, 'be_empty') end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/be_eq.rb000066400000000000000000000024241512756157400241710ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check for expectations where `be(...)` can replace `eq(...)`. # # The `be` matcher compares by identity while the `eq` matcher compares # using `==`. Booleans and nil can be compared by identity and therefore # the `be` matcher is preferable as it is a more strict test. # # @safety # This cop is unsafe because it changes how values are compared. # # @example # # bad # expect(foo).to eq(true) # expect(foo).to eq(false) # expect(foo).to eq(nil) # # # good # expect(foo).to be(true) # expect(foo).to be(false) # expect(foo).to be(nil) # class BeEq < Base extend AutoCorrector MSG = 'Prefer `be` over `eq`.' RESTRICT_ON_SEND = %i[eq].freeze # @!method eq_type_with_identity?(node) def_node_matcher :eq_type_with_identity?, <<~PATTERN (send nil? :eq {boolean nil}) PATTERN def on_send(node) return unless eq_type_with_identity?(node) add_offense(node.loc.selector) do |corrector| corrector.replace(node.loc.selector, 'be') end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/be_eql.rb000066400000000000000000000037011512756157400243440ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check for expectations where `be(...)` can replace `eql(...)`. # # The `be` matcher compares by identity while the `eql` matcher # compares using `eql?`. Integers, floats, booleans, symbols, and nil # can be compared by identity and therefore the `be` matcher is # preferable as it is a more strict test. # # @safety # This cop is unsafe because it changes how values are compared. # # @example # # bad # expect(foo).to eql(1) # expect(foo).to eql(1.0) # expect(foo).to eql(true) # expect(foo).to eql(false) # expect(foo).to eql(:bar) # expect(foo).to eql(nil) # # # good # expect(foo).to be(1) # expect(foo).to be(1.0) # expect(foo).to be(true) # expect(foo).to be(false) # expect(foo).to be(:bar) # expect(foo).to be(nil) # # This cop only looks for instances of `expect(...).to eql(...)`. We # do not check `to_not` or `not_to` since `!eql?` is more strict # than `!equal?`. We also do not try to flag `eq` because if # `a == b`, and `b` is comparable by identity, `a` is still not # necessarily the same type as `b` since the `#==` operator can # coerce objects for comparison. # class BeEql < Base extend AutoCorrector MSG = 'Prefer `be` over `eql`.' RESTRICT_ON_SEND = %i[to].freeze # @!method eql_type_with_identity(node) def_node_matcher :eql_type_with_identity, <<~PATTERN (send _ :to $(send nil? :eql {boolean int float sym nil})) PATTERN def on_send(node) eql_type_with_identity(node) do |eql| add_offense(eql.loc.selector) do |corrector| corrector.replace(eql.loc.selector, 'be') end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/be_nil.rb000066400000000000000000000036661512756157400243570ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Ensures a consistent style is used when matching `nil`. # # You can either use the more specific `be_nil` matcher, or the more # generic `be` matcher with a `nil` argument. # # This cop can be configured using the `EnforcedStyle` option # # @example `EnforcedStyle: be_nil` (default) # # bad # expect(foo).to be(nil) # # # good # expect(foo).to be_nil # # @example `EnforcedStyle: be` # # bad # expect(foo).to be_nil # # # good # expect(foo).to be(nil) # class BeNil < Base extend AutoCorrector include ConfigurableEnforcedStyle BE_MSG = 'Prefer `be(nil)` over `be_nil`.' BE_NIL_MSG = 'Prefer `be_nil` over `be(nil)`.' RESTRICT_ON_SEND = %i[be be_nil].freeze # @!method be_nil_matcher?(node) def_node_matcher :be_nil_matcher?, <<~PATTERN (send nil? :be_nil) PATTERN # @!method nil_value_expectation?(node) def_node_matcher :nil_value_expectation?, <<~PATTERN (send nil? :be nil) PATTERN def on_send(node) case style when :be check_be_style(node) when :be_nil check_be_nil_style(node) else # :nocov: :noop # :nocov: end end private def check_be_style(node) return unless be_nil_matcher?(node) add_offense(node, message: BE_MSG) do |corrector| corrector.replace(node, 'be(nil)') end end def check_be_nil_style(node) return unless nil_value_expectation?(node) add_offense(node, message: BE_NIL_MSG) do |corrector| corrector.replace(node, 'be_nil') end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/before_after_all.rb000066400000000000000000000025501512756157400263710ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that before/after(:all/:context) isn't being used. # # @example # # bad - Faster but risk of state leaking between examples # describe MyClass do # before(:all) { Widget.create } # after(:context) { Widget.delete_all } # end # # # good - Slower but examples are properly isolated # describe MyClass do # before(:each) { Widget.create } # after(:each) { Widget.delete_all } # end # class BeforeAfterAll < Base MSG = 'Beware of using `%s` as it may cause state to leak ' \ 'between tests. If you are using `rspec-rails`, and ' \ '`use_transactional_fixtures` is enabled, then records created ' \ 'in `%s` are not automatically rolled back.' RESTRICT_ON_SEND = Set[:before, :after].freeze # @!method before_or_after_all(node) def_node_matcher :before_or_after_all, <<~PATTERN $(send _ RESTRICT_ON_SEND (sym {:all :context})) PATTERN def on_send(node) before_or_after_all(node) do |hook| add_offense( node, message: format(MSG, hook: hook.source) ) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/change_by_zero.rb000066400000000000000000000135571512756157400261050ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Prefer negated matchers over `to change.by(0)`. # # In the case of composite expectations, cop suggest using the # negation matchers of `RSpec::Matchers#change`. # # By default the cop does not support autocorrect of # compound expectations, but if you set the # negated matcher for `change`, e.g. `not_change` with # the `NegatedMatcher` option, the cop will perform the autocorrection. # # @example NegatedMatcher: ~ (default) # # bad # expect { run }.to change(Foo, :bar).by(0) # expect { run }.to change { Foo.bar }.by(0) # # # bad - compound expectations (does not support autocorrection) # expect { run } # .to change(Foo, :bar).by(0) # .and change(Foo, :baz).by(0) # expect { run } # .to change { Foo.bar }.by(0) # .and change { Foo.baz }.by(0) # # # good # expect { run }.not_to change(Foo, :bar) # expect { run }.not_to change { Foo.bar } # # # good - compound expectations # define_negated_matcher :not_change, :change # expect { run } # .to not_change(Foo, :bar) # .and not_change(Foo, :baz) # expect { run } # .to not_change { Foo.bar } # .and not_change { Foo.baz } # # @example NegatedMatcher: not_change # # bad (support autocorrection to good case) # expect { run } # .to change(Foo, :bar).by(0) # .and change(Foo, :baz).by(0) # expect { run } # .to change { Foo.bar }.by(0) # .and change { Foo.baz }.by(0) # # # good # define_negated_matcher :not_change, :change # expect { run } # .to not_change(Foo, :bar) # .and not_change(Foo, :baz) # expect { run } # .to not_change { Foo.bar } # .and not_change { Foo.baz } # class ChangeByZero < Base extend AutoCorrector include RangeHelp MSG = 'Prefer `not_to change` over `to %s.by(0)`.' MSG_COMPOUND = 'Prefer %s with compound expectations ' \ 'over `%s.by(0)`.' CHANGE_METHODS = Set[:change, :a_block_changing, :changing].freeze RESTRICT_ON_SEND = CHANGE_METHODS.freeze # @!method expect_change_with_arguments(node) def_node_matcher :expect_change_with_arguments, <<~PATTERN (send $(send nil? CHANGE_METHODS ...) :by (int 0)) PATTERN # @!method expect_change_with_block(node) def_node_matcher :expect_change_with_block, <<~PATTERN (send (block $(send nil? CHANGE_METHODS) (args) (send (...) _)) :by (int 0)) PATTERN # @!method change_nodes(node) def_node_search :change_nodes, <<~PATTERN $(send nil? CHANGE_METHODS ...) PATTERN def on_send(node) expect_change_with_arguments(node.parent) do |change| register_offense(node.parent, change) end expect_change_with_block(node.parent.parent) do |change| register_offense(node.parent.parent, change) end end private def register_offense(node, change_node) return unless node.parent.send_type? if compound_expectations?(node) add_offense(node, message: message_compound(change_node)) do |corrector| autocorrect_compound(corrector, node) end else add_offense(node, message: message(change_node)) do |corrector| autocorrect(corrector, node, change_node) end end end def compound_expectations?(node) %i[and or & |].include?(node.parent.method_name) end def message(change_node) format(MSG, method: change_node.method_name) end def message_compound(change_node) format(MSG_COMPOUND, preferred: preferred_method, method: change_node.method_name) end def autocorrect(corrector, node, change_node) corrector.replace(node.parent.loc.selector, 'not_to') corrector.replace(change_node.loc.selector, 'change') range = node.loc.dot.with(end_pos: node.source_range.end_pos) corrector.remove(range) end def autocorrect_compound(corrector, node) return unless negated_matcher change_nodes(node) do |change_node| corrector.replace(change_node.loc.selector, negated_matcher) insert_operator(corrector, node, change_node) remove_by_zero(corrector, node, change_node) end end def insert_operator(corrector, node, change_node) operator = node.right_siblings.first return unless %i[& |].include?(operator) corrector.insert_after( replace_node(node, change_node), " #{operator}" ) end def replace_node(node, change_node) expect_change_with_arguments(node) ? change_node : change_node.parent end def remove_by_zero(corrector, node, change_node) range = node.loc.dot.with(end_pos: node.source_range.end_pos) if change_node.loc.line == range.line corrector.remove(range) else corrector.remove( range_by_whole_lines(range, include_final_newline: true) ) end end def negated_matcher cop_config['NegatedMatcher'] end def preferred_method negated_matcher ? "`#{negated_matcher}`" : 'negated matchers' end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/class_check.rb000066400000000000000000000045321512756157400253620ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Enforces consistent use of `be_a` or `be_kind_of`. # # @example EnforcedStyle: be_a (default) # # bad # expect(object).to be_kind_of(String) # expect(object).to be_a_kind_of(String) # # # good # expect(object).to be_a(String) # expect(object).to be_an(String) # # @example EnforcedStyle: be_kind_of # # bad # expect(object).to be_a(String) # expect(object).to be_an(String) # # # good # expect(object).to be_kind_of(String) # expect(object).to be_a_kind_of(String) # class ClassCheck < Base extend AutoCorrector include ConfigurableEnforcedStyle MSG = 'Prefer `%s` over `%s`.' METHOD_NAMES_FOR_BE_A = ::Set[ :be_a, :be_an ].freeze METHOD_NAMES_FOR_KIND_OF = ::Set[ :be_a_kind_of, :be_kind_of ].freeze PREFERRED_METHOD_NAME_BY_STYLE = { be_a: :be_a, be_kind_of: :be_kind_of }.freeze RESTRICT_ON_SEND = %i[ be_a be_a_kind_of be_an be_kind_of ].freeze def on_send(node) return unless offending?(node) add_offense( node.loc.selector, message: format_message(node) ) do |corrector| autocorrect(corrector, node) end end private def autocorrect(corrector, node) corrector.replace(node.loc.selector, preferred_method_name) end def format_message(node) format( MSG, current: node.method_name, preferred: preferred_method_name ) end def offending?(node) !node.receiver && !preferred_method_name?(node.method_name) end def preferred_method_name?(method_name) preferred_method_names.include?(method_name) end def preferred_method_name PREFERRED_METHOD_NAME_BY_STYLE[style] end def preferred_method_names if style == :be_a METHOD_NAMES_FOR_BE_A else METHOD_NAMES_FOR_KIND_OF end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/contain_exactly.rb000066400000000000000000000027421512756157400263050ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks where `contain_exactly` is used. # # This cop checks for the following: # # - Prefer `match_array` when matching array values. # - Prefer `be_empty` when using `contain_exactly` with no arguments. # # @example # # bad # it { is_expected.to contain_exactly(*array1, *array2) } # # # good # it { is_expected.to match_array(array1 + array2) } # # # good # it { is_expected.to contain_exactly(content, *array) } # class ContainExactly < Base extend AutoCorrector MSG = 'Prefer `match_array` when matching array values.' RESTRICT_ON_SEND = %i[contain_exactly].freeze def on_send(node) return if node.arguments.empty? check_populated_collection(node) end private def check_populated_collection(node) return unless node.each_child_node.all?(&:splat_type?) add_offense(node) do |corrector| autocorrect_for_populated_array(node, corrector) end end def autocorrect_for_populated_array(node, corrector) arrays = node.arguments.map do |splat_node| splat_node.children.first end corrector.replace( node, "match_array(#{arrays.map(&:source).join(' + ')})" ) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/context_method.rb000066400000000000000000000024071512756157400261430ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # `context` should not be used for specifying methods. # # @example # # bad # context '#foo_bar' do # # ... # end # # context '.foo_bar' do # # ... # end # # # good # describe '#foo_bar' do # # ... # end # # describe '.foo_bar' do # # ... # end # class ContextMethod < Base extend AutoCorrector MSG = 'Use `describe` for testing methods.' # @!method context_method(node) def_node_matcher :context_method, <<~PATTERN (block (send #rspec? :context ${(str #method_name?) (dstr (str #method_name?) ...)} ...) ...) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_method(node) do |context| add_offense(context) do |corrector| corrector.replace(node.send_node.loc.selector, 'describe') end end end private def method_name?(description) description.start_with?('.', '#') end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/context_wording.rb000066400000000000000000000071661512756157400263430ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that `context` docstring starts with an allowed prefix. # # The default list of prefixes is minimal. Users are encouraged to tailor # the configuration to meet project needs. Other acceptable prefixes may # include `if`, `unless`, `for`, `before`, `after`, or `during`. # They may consist of multiple words if desired. # # @see http://www.betterspecs.org/#contexts # # If both `Prefixes` and `AllowedPatterns` are empty, this cop will always # report an offense. So you need to set at least one of them. # # @example `Prefixes` configuration # # .rubocop.yml # # RSpec/ContextWording: # # Prefixes: # # - when # # - with # # - without # # - if # # - unless # # - for # # @example # # bad # context 'the display name not present' do # # ... # end # # # good # context 'when the display name is not present' do # # ... # end # # This cop can be customized allowed context description pattern # with `AllowedPatterns`. By default, there are no checking by pattern. # # @example `AllowedPatterns` configuration # # # .rubocop.yml # # RSpec/ContextWording: # # AllowedPatterns: # # - とき$ # # @example # # bad # context '条件を満たす' do # # ... # end # # # good # context '条件を満たすとき' do # # ... # end # class ContextWording < Base include AllowedPattern MSG_MATCH = 'Context description should match %s.' MSG_ALWAYS = 'Current settings will always report an offense. Please ' \ 'add allowed words to `Prefixes` or `AllowedPatterns`.' # @!method context_wording(node) def_node_matcher :context_wording, <<~PATTERN (block (send #rspec? { :context :shared_context } $(any_str ...) ...) ...) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_wording(node) do |context| unless matches_allowed_pattern?(description(context)) add_offense(context, message: message) end end end private def allowed_patterns super + prefix_regexes end def prefix_regexes @prefix_regexes ||= prefixes.map { |pre| /^#{Regexp.escape(pre)}\b/ } end def description(context) if context.xstr_type? context.value.value else context.value end end def message if allowed_patterns.empty? MSG_ALWAYS else format(MSG_MATCH, patterns: expect_patterns) end end def expect_patterns inspected = allowed_patterns.map do |pattern| pattern.inspect.gsub(/\A"|"\z/, '/') end return inspected.first if inspected.size == 1 inspected << "or #{inspected.pop}" inspected.join(', ') end def prefixes Array(cop_config.fetch('Prefixes', [])).tap do |prefixes| non_strings = prefixes.reject { |pre| pre.is_a?(String) } unless non_strings.empty? raise "Non-string prefixes #{non_strings.inspect} detected." end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/describe_class.rb000066400000000000000000000045101512756157400260610ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that the first argument to the top-level describe is a constant. # # It can be configured to ignore strings when certain metadata is passed. # # Ignores Rails and Aruba `type` metadata by default. # # @example `IgnoredMetadata` configuration # # .rubocop.yml # # RSpec/DescribeClass: # # IgnoredMetadata: # # type: # # - request # # - controller # # @example # # bad # describe 'Do something' do # end # # # good # describe TestedClass do # subject { described_class } # end # # describe 'TestedClass::VERSION' do # subject { Object.const_get(self.class.description) } # end # # describe "A feature example", type: :feature do # end # class DescribeClass < Base include TopLevelGroup MSG = 'The first argument to describe should be ' \ 'the class or module being tested.' # @!method example_group_with_ignored_metadata?(node) def_node_matcher :example_group_with_ignored_metadata?, <<~PATTERN (send #rspec? :describe ... (hash <#ignored_metadata? ...>)) PATTERN # @!method not_a_const_described(node) def_node_matcher :not_a_const_described, <<~PATTERN (send #rspec? :describe $[!const !#string_constant?] ...) PATTERN # @!method sym_pair(node) def_node_matcher :sym_pair, <<~PATTERN (pair $sym $sym) PATTERN def on_top_level_group(node) return if example_group_with_ignored_metadata?(node.send_node) not_a_const_described(node.send_node) do |described| add_offense(described) end end private def ignored_metadata?(node) sym_pair(node) do |key, value| ignored_metadata[key.value.to_s].to_a.include?(value.value.to_s) end end def string_constant?(described) described.str_type? && described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/) end def ignored_metadata cop_config['IgnoredMetadata'] || {} end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/describe_method.rb000066400000000000000000000025411512756157400262360ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that the second argument to `describe` specifies a method. # # @example # # bad # describe MyClass, 'do something' do # end # # # good # describe MyClass, '#my_instance_method' do # end # # describe MyClass, '.my_class_method' do # end # class DescribeMethod < Base include TopLevelGroup MSG = 'The second argument to describe should be the method ' \ "being tested. '#instance' or '.class'." # @!method second_string_literal_argument(node) def_node_matcher :second_string_literal_argument, <<~PATTERN (block (send #rspec? :describe _first_argument ${str dstr} ...) ...) PATTERN # @!method method_name?(node) def_node_matcher :method_name?, <<~PATTERN {(str #method_name_prefix?) (dstr (str #method_name_prefix?) ...)} PATTERN def on_top_level_group(node) second_string_literal_argument(node) do |argument| add_offense(argument) unless method_name?(argument) end end private def method_name_prefix?(description) description.start_with?('.', '#') end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/describe_symbol.rb000066400000000000000000000014561512756157400262670ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Avoid describing symbols. # # @example # # bad # describe :my_method do # # ... # end # # # good # describe '#my_method' do # # ... # end # # @see https://github.com/rspec/rspec-core/issues/1610 class DescribeSymbol < Base MSG = 'Avoid describing symbols.' RESTRICT_ON_SEND = %i[describe].freeze # @!method describe_symbol?(node) def_node_matcher :describe_symbol?, <<~PATTERN (send #rspec? :describe $sym ...) PATTERN def on_send(node) describe_symbol?(node) do |match| add_offense(match) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/described_class.rb000066400000000000000000000176711512756157400262410ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that tests use `described_class`. # # If the first argument of describe is a class, the class is exposed to # each example via described_class. # # This cop can be configured using the `EnforcedStyle`, `SkipBlocks` # and `OnlyStaticConstants` options. # `OnlyStaticConstants` is only relevant when `EnforcedStyle` is # `described_class`. # # There's a known caveat with rspec-rails's `controller` helper that # runs its block in a different context, and `described_class` is not # available to it. `SkipBlocks` option excludes detection in all # non-RSpec related blocks. # # To narrow down this setting to only a specific directory, it is # possible to use an overriding configuration file local to that # directory. # # @safety # Autocorrection is unsafe when `SkipBlocks: false` because # `described_class` might not be available within the block (for # example, in rspec-rails's `controller` helper). # # @example `EnforcedStyle: described_class` (default) # # bad # describe MyClass do # subject { MyClass.do_something } # end # # # good # describe MyClass do # subject { described_class.do_something } # end # # @example `OnlyStaticConstants: true` (default) # # good # describe MyClass do # subject { MyClass::CONSTANT } # end # # @example `OnlyStaticConstants: false` # # bad # describe MyClass do # subject { MyClass::CONSTANT } # end # # @example `EnforcedStyle: explicit` # # bad # describe MyClass do # subject { described_class.do_something } # end # # # good # describe MyClass do # subject { MyClass.do_something } # end # # @example `SkipBlocks: true` # # spec/controllers/.rubocop.yml # # RSpec/DescribedClass: # # SkipBlocks: true # # # acceptable # describe MyConcern do # controller(ApplicationController) do # include MyConcern # end # end # class DescribedClass < Base # rubocop:disable Metrics/ClassLength extend AutoCorrector include ConfigurableEnforcedStyle include Namespace DESCRIBED_CLASS = 'described_class' MSG = 'Use `%s` instead of `%s`.' # @!method common_instance_exec_closure?(node) def_node_matcher :common_instance_exec_closure?, <<~PATTERN (block { (send (const nil? {:Class :Module :Struct}) :new ...) (send (const nil? :Data) :define ...) (send _ {:class_eval :module_eval :instance_eval} ...) (send _ {:class_exec :module_exec :instance_exec} ...) } ... ) PATTERN # @!method rspec_block?(node) def_node_matcher :rspec_block?, '(any_block (send #rspec? #ALL.all ...) ...)' # @!method scope_changing_syntax?(node) def_node_matcher :scope_changing_syntax?, '{def class module}' # @!method described_constant(node) def_node_matcher :described_constant, <<~PATTERN (block (send _ :describe $(const ...) ...) (args) $_) PATTERN # @!method contains_described_class?(node) def_node_search :contains_described_class?, '(send nil? :described_class)' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler # In case the explicit style is used, we need to remember what's # being described. @described_class, body = described_constant(node) return unless body find_usage(body) do |match| msg = message(match.const_name) add_offense(match, message: msg) do |corrector| autocorrect(corrector, match) end end end private def autocorrect(corrector, match) replacement = if style == :described_class DESCRIBED_CLASS else @described_class.const_name end corrector.replace(match, replacement) end def find_usage(node, &block) yield(node) if offensive?(node) return if scope_change?(node) || allowed?(node) node.each_child_node do |child| find_usage(child, &block) end end def allowed?(node) node.const_type? && only_static_constants? end def message(offense) if style == :described_class format(MSG, replacement: DESCRIBED_CLASS, src: offense) else format(MSG, replacement: @described_class.const_name, src: DESCRIBED_CLASS) end end def scope_change?(node) scope_changing_syntax?(node) || common_instance_exec_closure?(node) || skippable_block?(node) end def skippable_block?(node) return false unless cop_config['SkipBlocks'] node.any_block_type? && !rspec_block?(node) end def only_static_constants? cop_config.fetch('OnlyStaticConstants', true) end def offensive?(node) if style == :described_class offensive_described_class?(node) else node.send_type? && node.method?(:described_class) end end def offensive_described_class?(node) return false unless node.const_type? # E.g. `described_class::CONSTANT` return false if contains_described_class?(node) nearest_described_class, = node.each_ancestor(:block) .map { |ancestor| described_constant(ancestor) }.find(&:itself) return false if nearest_described_class.equal?(node) full_const_name(nearest_described_class) == full_const_name(node) end def full_const_name(node) symbolized_namespace = namespace(node).map(&:to_sym) collapse_namespace(symbolized_namespace, const_name(node)) end # @param namespace [Array] # @param const [Array] # @return [Array] # @example # # nil represents base constant # collapse_namespace([], [:C]) # => [:C] # collapse_namespace([:A, :B], [:C]) # => [:A, :B, :C] # collapse_namespace([:A, :B], [:B, :C]) # => [:A, :B, :C] # collapse_namespace([:A, :B], [nil, :C]) # => [nil, :C] # collapse_namespace([:A, :B], [nil, :B, :C]) # => [nil, :B, :C] def collapse_namespace(namespace, const) return const if namespace.empty? || const.first.nil? start = [0, (namespace.length - const.length)].max max = namespace.length intersection = (start..max).find do |shift| namespace[shift, max - shift] == const[0, max - shift] end [*namespace[0, intersection], *const] end # @param node [RuboCop::AST::Node] # @return [Array] # @example # const_name(s(:const, nil, :C)) # => [:C] # const_name(s(:const, s(:const, nil, :M), :C)) # => [:M, :C] # const_name(s(:const, s(:cbase), :C)) # => [nil, :C] def const_name(node) namespace = node.namespace name = node.short_name if !namespace [name] elsif namespace.const_type? [*const_name(namespace), name] elsif %i[lvar cbase send].include?(namespace.type) [nil, name] end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/described_class_module_wrapping.rb000066400000000000000000000016451512756157400315070ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Avoid opening modules and defining specs within them. # # @example # # bad # module MyModule # RSpec.describe MyClass do # # ... # end # end # # # good # RSpec.describe MyModule::MyClass do # # ... # end # # @see https://github.com/rubocop/rubocop-rspec/issues/735 class DescribedClassModuleWrapping < Base MSG = 'Avoid opening modules and defining specs within them.' # @!method include_rspec_blocks?(node) def_node_search :include_rspec_blocks?, <<~PATTERN (any_block (send #explicit_rspec? #ExampleGroups.all ...) ...) PATTERN def on_module(node) return unless include_rspec_blocks?(node) add_offense(node) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/dialect.rb000066400000000000000000000050241512756157400245220ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Enforces custom RSpec dialects. # # A dialect can be based on the following RSpec methods: # # - describe, context, feature, example_group # - xdescribe, xcontext, xfeature # - fdescribe, fcontext, ffeature # - shared_examples, shared_examples_for, shared_context # - it, specify, example, scenario, its # - fit, fspecify, fexample, fscenario, focus # - xit, xspecify, xexample, xscenario, skip # - pending # - prepend_before, before, append_before, # - around # - prepend_after, after, append_after # - let, let! # - subject, subject! # - expect, is_expected, expect_any_instance_of # - raise_error, raise_exception # # By default all of the RSpec methods and aliases are allowed. By setting # a config like: # # RSpec/Dialect: # PreferredMethods: # context: describe # # If you were previously using the `RSpec/Capybara/FeatureMethods` cop and # want to keep disabling all Capybara-specific methods that have the same # native RSpec method (e.g. are just aliases), use the following config: # # RSpec/Dialect: # PreferredMethods: # background: :before # scenario: :it # xscenario: :xit # given: :let # given!: :let! # feature: :describe # # You can expect the following behavior: # # @example # # bad # context 'display name presence' do # # ... # end # # # good # describe 'display name presence' do # # ... # end # class Dialect < Base extend AutoCorrector include MethodPreference MSG = 'Prefer `%s` over `%s`.' # @!method rspec_method?(node) def_node_matcher :rspec_method?, '(send #rspec? #ALL.all ...)' def on_send(node) return unless rspec_method?(node) return unless preferred_methods[node.method_name] msg = format(MSG, prefer: preferred_method(node.method_name), current: node.method_name) add_offense(node, message: msg) do |corrector| current = node.loc.selector preferred = preferred_method(current.source) corrector.replace(current, preferred) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/duplicated_metadata.rb000066400000000000000000000023041512756157400270710ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Avoid duplicated metadata. # # @example # # bad # describe 'Something', :a, :a # # # good # describe 'Something', :a class DuplicatedMetadata < Base extend AutoCorrector include Metadata include RangeHelp MSG = 'Avoid duplicated metadata.' def on_metadata(symbols, _hash) symbols.each do |symbol| on_metadata_symbol(symbol) end end private def on_metadata_symbol(node) return unless duplicated?(node) add_offense(node) do |corrector| autocorrect(corrector, node) end end def autocorrect(corrector, node) corrector.remove( range_with_surrounding_comma( range_with_surrounding_space( node.source_range, side: :left ), :left ) ) end def duplicated?(node) node.left_siblings.any? do |sibling| sibling.eql?(node) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_example_group.rb000066400000000000000000000136001512756157400272010ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if an example group does not include any tests. # # @example usage # # bad # describe Bacon do # let(:bacon) { Bacon.new(chunkiness) } # let(:chunkiness) { false } # # context 'extra chunky' do # flagged by rubocop # let(:chunkiness) { true } # end # # it 'is chunky' do # expect(bacon.chunky?).to be_truthy # end # end # # # good # describe Bacon do # let(:bacon) { Bacon.new(chunkiness) } # let(:chunkiness) { false } # # it 'is chunky' do # expect(bacon.chunky?).to be_truthy # end # end # # # good # describe Bacon do # pending 'will add tests later' # end # class EmptyExampleGroup < Base extend AutoCorrector include RangeHelp MSG = 'Empty example group detected.' # @!method example_group_body(node) # Match example group blocks and yield their body # # @example source that matches # describe 'example group' do # it { is_expected.to be } # end # # @param node [RuboCop::AST::Node] # @yield [RuboCop::AST::Node] example group body def_node_matcher :example_group_body, <<~PATTERN (block (send #rspec? #ExampleGroups.all ...) args $_) PATTERN # @!method example_or_group_or_include?(node) # Match examples, example groups and includes # # @example source that matches # it { is_expected.to fly } # describe('non-empty example groups too') { } # it_behaves_like 'an animal' # it_behaves_like('a cat') { let(:food) { 'milk' } } # it_has_root_access # skip # it 'will be implemented later' # # @param node [RuboCop::AST::Node] # @return [Array] matching nodes def_node_matcher :example_or_group_or_include?, <<~PATTERN { (block (send #rspec? {#Examples.all #ExampleGroups.all #Includes.all} ...) ...) (send nil? {#Examples.all #Includes.all} ...) } PATTERN # @!method examples_inside_block?(node) # Match examples defined inside a block which is not a hook # # @example source that matches # %w(r g b).each do |color| # it { is_expected.to have_color(color) } # end # # @example source that does not match # before do # it { is_expected.to fall_into_oblivion } # end # # @param node [RuboCop::AST::Node] # @return [Array] matching nodes def_node_matcher :examples_inside_block?, <<~PATTERN (block !(send nil? #Hooks.all ...) _ #examples?) PATTERN # @!method examples_directly_or_in_block?(node) # Match examples or examples inside blocks # # @example source that matches # it { expect(drink).to be_cold } # context('when winter') { it { expect(drink).to be_hot } } # (1..5).each { |divisor| it { is_expected.to divide_by(divisor) } } # # @param node [RuboCop::AST::Node] # @return [Array] matching nodes def_node_matcher :examples_directly_or_in_block?, <<~PATTERN { #example_or_group_or_include? #examples_inside_block? } PATTERN # @!method examples?(node) # Matches examples defined in scopes where they could run # # @example source that matches # it { expect(myself).to be_run } # describe { it { i_run_as_well } } # # @example source that does not match # before { it { whatever here won't run anyway } } # # @param node [RuboCop::AST::Node] # @return [Array] matching nodes def_node_matcher :examples?, <<~PATTERN { #examples_directly_or_in_block? #examples_in_branches? (begin <#examples_directly_or_in_block? ...>) (begin <#examples_in_branches? ...>) } PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return if node.each_ancestor(:any_def).any? return if node.each_ancestor(:block).any? { |block| example?(block) } example_group_body(node) do |body| next unless offensive?(body) add_offense(node.send_node) do |corrector| corrector.remove(removed_range(node)) end end end private def offensive?(body) return true unless body return false if conditionals_with_examples?(body) if body.type?(:if, :case) !examples_in_branches?(body) else !examples?(body) end end def conditionals_with_examples?(body) return false unless body.type?(:begin, :case) body.each_descendant(:if, :case).any? do |condition_node| examples_in_branches?(condition_node) end end def examples_in_branches?(condition_node) return false unless condition_node return false unless condition_node.type?(:if, :case) condition_node.branches.any? { |branch| examples?(branch) } end def removed_range(node) range_by_whole_lines( node.source_range, include_final_newline: true ) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_hook.rb000066400000000000000000000022021512756157400252660ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for empty before and after hooks. # # @example # # bad # before {} # after do; end # before(:all) do # end # after(:all) { } # # # good # before { create_users } # after do # cleanup_users # end # before(:all) do # create_feed # end # after(:all) { cleanup_feed } # class EmptyHook < Base extend AutoCorrector include RuboCop::Cop::RangeHelp MSG = 'Empty hook detected.' # @!method empty_hook?(node) def_node_matcher :empty_hook?, <<~PATTERN (block $(send nil? #Hooks.all ...) _ nil?) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler empty_hook?(node) do |hook| add_offense(hook) do |corrector| corrector.remove( range_with_surrounding_space(node.source_range, side: :left) ) end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_line_after_example.rb000066400000000000000000000037501512756157400301620ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if there is an empty line after example blocks. # # @example # # bad # RSpec.describe Foo do # it 'does this' do # end # it 'does that' do # end # end # # # good # RSpec.describe Foo do # it 'does this' do # end # # it 'does that' do # end # end # # # fair - it's ok to have non-separated one-liners # RSpec.describe Foo do # it { one } # it { two } # end # # @example with AllowConsecutiveOneLiners configuration # # rubocop.yml # # RSpec/EmptyLineAfterExample: # # AllowConsecutiveOneLiners: false # # # bad # RSpec.describe Foo do # it { one } # it { two } # end # class EmptyLineAfterExample < Base extend AutoCorrector include EmptyLineSeparation MSG = 'Add an empty line after `%s`.' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) return if allowed_one_liner?(node) missing_separating_line_offense(node) do |method| format(MSG, example: method) end end private def allowed_one_liner?(node) consecutive_one_liner?(node) && allow_consecutive_one_liners? end def allow_consecutive_one_liners? cop_config['AllowConsecutiveOneLiners'] end def consecutive_one_liner?(node) node.single_line? && next_one_line_example?(node) end def next_one_line_example?(node) next_sibling = node.right_sibling return false unless next_sibling return false unless example?(next_sibling) next_sibling.single_line? end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_line_after_example_group.rb000066400000000000000000000017021512756157400313710ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if there is an empty line after example group blocks. # # @example # # bad # RSpec.describe Foo do # describe '#bar' do # end # describe '#baz' do # end # end # # # good # RSpec.describe Foo do # describe '#bar' do # end # # describe '#baz' do # end # end # class EmptyLineAfterExampleGroup < Base extend AutoCorrector include EmptyLineSeparation MSG = 'Add an empty line after `%s`.' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless spec_group?(node) missing_separating_line_offense(node) do |method| format(MSG, example_group: method) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_line_after_final_let.rb000066400000000000000000000017411512756157400304620ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if there is an empty line after the last let block. # # @example # # bad # let(:foo) { bar } # let(:something) { other } # it { does_something } # # # good # let(:foo) { bar } # let(:something) { other } # # it { does_something } # class EmptyLineAfterFinalLet < Base extend AutoCorrector include EmptyLineSeparation MSG = 'Add an empty line after the last `%s`.' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group_with_body?(node) final_let = node.body.child_nodes.reverse.find { |child| let?(child) } return if final_let.nil? missing_separating_line_offense(final_let) do |method| format(MSG, let: method) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_line_after_hook.rb000066400000000000000000000040011512756157400274550ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if there is an empty line after hook blocks. # # `AllowConsecutiveOneLiners` configures whether adjacent # one-line definitions are considered an offense. # # @example # # bad # before { do_something } # it { does_something } # # # bad # after { do_something } # it { does_something } # # # bad # around { |test| test.run } # it { does_something } # # # good # after { do_something } # # it { does_something } # # # fair - it's ok to have non-separated one-liners hooks # around { |test| test.run } # after { do_something } # # it { does_something } # # @example with AllowConsecutiveOneLiners configuration # # rubocop.yml # # RSpec/EmptyLineAfterHook: # # AllowConsecutiveOneLiners: false # # # bad # around { |test| test.run } # after { do_something } # # it { does_something } # # # good # around { |test| test.run } # # after { do_something } # # it { does_something } # class EmptyLineAfterHook < Base extend AutoCorrector include ConfigurableEnforcedStyle include EmptyLineSeparation MSG = 'Add an empty line after `%s`.' def on_block(node) return unless hook?(node) return if cop_config['AllowConsecutiveOneLiners'] && chained_single_line_hooks?(node) missing_separating_line_offense(node) do |method| format(MSG, hook: method) end end alias on_numblock on_block private def chained_single_line_hooks?(node) next_node = node.right_sibling hook?(next_node) && node.single_line? && next_node.single_line? end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_line_after_subject.rb000066400000000000000000000015661512756157400301710ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if there is an empty line after subject block. # # @example # # bad # subject(:obj) { described_class } # let(:foo) { bar } # # # good # subject(:obj) { described_class } # # let(:foo) { bar } # class EmptyLineAfterSubject < Base extend AutoCorrector include EmptyLineSeparation include InsideExampleGroup MSG = 'Add an empty line after `%s`.' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless subject?(node) return unless inside_example_group?(node) missing_separating_line_offense(node) do |method| format(MSG, subject: method) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_metadata.rb000066400000000000000000000020241512756157400261100ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Avoid empty metadata hash. # # @example EnforcedStyle: symbol (default) # # bad # describe 'Something', {} # # # good # describe 'Something' class EmptyMetadata < Base extend AutoCorrector include Metadata include RangeHelp MSG = 'Avoid empty metadata hash.' def on_metadata(_symbols, hash) return unless hash&.pairs&.empty? return if hash.children.any?(&:kwsplat_type?) add_offense(hash) do |corrector| remove_empty_metadata(corrector, hash) end end private def remove_empty_metadata(corrector, node) corrector.remove( range_with_surrounding_comma( range_with_surrounding_space( node.source_range, side: :left ), :left ) ) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/empty_output.rb000066400000000000000000000024761512756157400257030ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that the `output` matcher is not called with an empty string. # # @example # # bad # expect { foo }.to output('').to_stdout # expect { bar }.not_to output('').to_stderr # # # good # expect { foo }.not_to output.to_stdout # expect { bar }.to output.to_stderr # class EmptyOutput < Base extend AutoCorrector MSG = 'Use `%s` instead of matching on an empty output.' RESTRICT_ON_SEND = Runners.all # @!method matching_empty_output(node) def_node_matcher :matching_empty_output, <<~PATTERN (send (block (send nil? :expect) ... ) #Runners.all (send $(send nil? :output (str empty?)) ...) ) PATTERN def on_send(send_node) matching_empty_output(send_node) do |node| runner = send_node.method?(:to) ? 'not_to' : 'to' message = format(MSG, runner: runner) add_offense(node, message: message) do |corrector| corrector.replace(send_node.loc.selector, runner) corrector.replace(node, 'output') end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/eq.rb000066400000000000000000000020571512756157400235250ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Use `eq` instead of `be ==` to compare objects. # # @example # # bad # expect(foo).to be == 42 # # # good # expect(foo).to eq 42 # class Eq < Base extend AutoCorrector include RangeHelp MSG = 'Use `eq` instead of `be ==` to compare objects.' RESTRICT_ON_SEND = Runners.all # @!method be_equals(node) def_node_matcher :be_equals, <<~PATTERN (send _ #Runners.all $(send (send nil? :be) :== _)) PATTERN def on_send(node) be_equals(node) do |matcher| range = offense_range(matcher) add_offense(range) do |corrector| corrector.replace(range, 'eq') end end end private def offense_range(matcher) range_between( matcher.source_range.begin_pos, matcher.loc.selector.end_pos ) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/example_length.rb000066400000000000000000000033541512756157400261150ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for long examples. # # A long example is usually more difficult to understand. Consider # extracting out some behavior, e.g. with a `let` block, or a helper # method. # # @example # # bad # it do # service = described_class.new # more_setup # more_setup # result = service.call # expect(result).to be(true) # end # # # good # it do # service = described_class.new # result = service.call # expect(result).to be(true) # end # # You can set constructs you want to fold with `CountAsOne`. # Available are: 'array', 'hash', 'heredoc', and 'method_call'. # Each construct will be counted as one line regardless of # its actual size. # # @example CountAsOne: ['array', 'heredoc', 'method_call'] # # it do # array = [ # +1 # 1, # 2 # ] # # hash = { # +3 # key: 'value' # } # # msg = <<~HEREDOC # +1 # Heredoc # content. # HEREDOC # # foo( # +1 # 1, # 2 # ) # end # 6 points # class ExampleLength < Base include CodeLength LABEL = 'Example' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) check_code_length(node) end private def cop_label LABEL end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/example_without_description.rb000066400000000000000000000055641512756157400307470ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for examples without a description. # # RSpec allows for auto-generated example descriptions when there is no # description provided or the description is an empty one. # It is acceptable to use `specify` without a description # # This cop removes empty descriptions. # It also defines whether auto-generated description is allowed, based # on the configured style. # # This cop can be configured using the `EnforcedStyle` option # # @example # # always good # specify do # result = service.call # expect(result).to be(true) # end # # @example `EnforcedStyle: always_allow` (default) # # bad # it('') { is_expected.to be_good } # specify '' do # result = service.call # expect(result).to be(true) # end # # # good # it { is_expected.to be_good } # specify do # result = service.call # expect(result).to be(true) # end # # @example `EnforcedStyle: single_line_only` # # bad # it('') { is_expected.to be_good } # it do # result = service.call # expect(result).to be(true) # end # # # good # it { is_expected.to be_good } # # @example `EnforcedStyle: disallow` # # bad # it { is_expected.to be_good } # it do # result = service.call # expect(result).to be(true) # end # class ExampleWithoutDescription < Base include ConfigurableEnforcedStyle MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \ 'have auto-generated description.' MSG_ADD_DESCRIPTION = 'Add a description.' # @!method example_description(node) def_node_matcher :example_description, '(send nil? _ $(str $_))' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) check_example_without_description(node.send_node) example_description(node.send_node) do |message_node, message| return unless message.to_s.empty? add_offense(message_node, message: MSG_DEFAULT_ARGUMENT) end end private def check_example_without_description(node) return if node.arguments? return unless disallow_empty_description?(node) return if node.method?(:specify) && node.parent.multiline? add_offense(node, message: MSG_ADD_DESCRIPTION) end def disallow_empty_description?(node) style == :disallow || (style == :single_line_only && node.parent.multiline?) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/example_wording.rb000066400000000000000000000121051512756157400262770ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for common mistakes in example descriptions. # # This cop will correct docstrings that begin with 'should' and 'it'. # This cop will also look for insufficient examples and call them out. # # @see http://betterspecs.org/#should # # @safety # The autocorrect is experimental - use with care! It can be configured # with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only). # # While the autocorrect will not break your code (it only modifies test # description strings, not the actual test logic), it may produce # grammatically incorrect English in some cases. Always review the diff # when using autocorrect to ensure the descriptions remain natural and # accurate. # # This is not classified as an unsafe autocorrect because it does not # affect code behavior, but manual review of changes is strongly # recommended. # # Use the DisallowedExamples setting to prevent unclear or insufficient # descriptions. Please note that this config will not be treated as # case sensitive. # # @example # # bad # it 'should find nothing' do # end # # it 'will find nothing' do # end # # # good # it 'finds nothing' do # end # # @example # # bad # it 'it does things' do # end # # # good # it 'does things' do # end # # @example `DisallowedExamples: ['works']` (default) # # bad # it 'works' do # end # # # good # it 'marks the task as done' do # end class ExampleWording < Base extend AutoCorrector MSG_SHOULD = 'Do not use should when describing your tests.' MSG_WILL = 'Do not use the future tense when describing your tests.' MSG_IT = "Do not repeat 'it' when describing your tests." MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \ 'insufficient.' SHOULD_PREFIX = /\Ashould(?:n't|n’t)?\b/i.freeze WILL_PREFIX = /\A(?:will|won't|won’t)\b/i.freeze IT_PREFIX = /\Ait /i.freeze # @!method it_description(node) def_node_matcher :it_description, <<~PATTERN (block (send _ :it ${ (str $_) (dstr (str $_ ) ...) } ...) ...) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler it_description(node) do |description_node, message| if message.match?(SHOULD_PREFIX) add_wording_offense(description_node, MSG_SHOULD) elsif message.match?(WILL_PREFIX) add_wording_offense(description_node, MSG_WILL) elsif message.match?(IT_PREFIX) add_wording_offense(description_node, MSG_IT) elsif insufficient_docstring?(description_node) add_offense(docstring(description_node), message: MSG_INSUFFICIENT_DESCRIPTION) end end end private def add_wording_offense(node, message) docstring = docstring(node) add_offense(docstring, message: message) do |corrector| next if node.heredoc? corrector.replace(docstring, replacement_text(node)) end end def docstring(node) expr = node.source_range Parser::Source::Range.new( expr.source_buffer, expr.begin_pos + 1, expr.end_pos - 1 ) end def replacement_text(node) text = text(node) if text.match?(SHOULD_PREFIX) || text.match?(WILL_PREFIX) RuboCop::RSpec::Wording.new( text, ignore: ignored_words, replace: custom_transform ).rewrite else text.sub(IT_PREFIX, '') end end # Recursive processing is required to process nested dstr nodes # that is the case for \-separated multiline strings with interpolation. def text(node) case node.type when :dstr node.node_parts.map { |child_node| text(child_node) }.join when :str node.value else node.source end end def custom_transform cop_config.fetch('CustomTransform', {}) end def ignored_words cop_config.fetch('IgnoredWords', []) end def insufficient_docstring?(description_node) insufficient_examples.include?(preprocess(text(description_node))) end def insufficient_examples examples = cop_config.fetch('DisallowedExamples', []) examples.map! { |example| preprocess(example) } end def preprocess(message) message.strip.squeeze(' ').downcase end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb000066400000000000000000000054101512756157400306720ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for excessive whitespace in example descriptions. # # @example # # bad # it ' has excessive spacing ' do # end # # # good # it 'has excessive spacing' do # end # # @example # # bad # context ' when a condition is met ' do # end # # # good # context 'when a condition is met' do # end # class ExcessiveDocstringSpacing < Base extend AutoCorrector MSG = 'Excessive whitespace.' # @!method example_description(node) def_node_matcher :example_description, <<~PATTERN (send #rspec? {#Examples.all #ExampleGroups.all} ${ $str $(dstr ({str dstr `sym} ...) ...) } ...) PATTERN def on_send(node) example_description(node) do |description_node, message| return if description_node.heredoc? text = text(message) return unless excessive_whitespace?(text) add_whitespace_offense(description_node, text) end end private # @param text [String] def excessive_whitespace?(text) text.match?(/ # Leading space \A[[:blank:]] | # Trailing space [[:blank:]]\z | # Two or more consecutive spaces, except if they are leading spaces [^[[:space:]]][[:blank:]]{2,}[^[[:blank:]]] /x) end # @param text [String] def strip_excessive_whitespace(text) text .gsub(/[[:blank:]]{2,}/, ' ') .gsub(/\A[[:blank:]]|[[:blank:]]\z/, '') end # @param node [RuboCop::AST::Node] # @param text [String] def add_whitespace_offense(node, text) docstring = docstring(node) corrected = strip_excessive_whitespace(text) add_offense(docstring) do |corrector| corrector.replace(docstring, corrected) end end def docstring(node) expr = node.source_range Parser::Source::Range.new( expr.source_buffer, expr.begin_pos + 1, expr.end_pos - 1 ) end # Recursive processing is required to process nested dstr nodes # that is the case for \-separated multiline strings with interpolation. def text(node) case node.type when :dstr node.node_parts.map { |child_node| text(child_node) }.join when :str, :sym node.value else node.source end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/expect_actual.rb000066400000000000000000000052611512756157400257410ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for `expect(...)` calls containing literal values. # # Autocorrection is performed when the expected is not a literal. # # @example # # bad # expect(5).to eq(price) # expect(/foo/).to eq(pattern) # expect("John").to eq(name) # # # good # expect(price).to eq(5) # expect(pattern).to eq(/foo/) # expect(name).to eq("John") # # # bad (not supported autocorrection) # expect(false).to eq(true) # class ExpectActual < Base extend AutoCorrector MSG = 'Provide the actual value you are testing to `expect(...)`.' RESTRICT_ON_SEND = Runners.all SIMPLE_LITERALS = %i[ true false nil int float str sym complex rational regopt ].freeze COMPLEX_LITERALS = %i[ array hash pair irange erange regexp ].freeze SKIPPED_MATCHERS = %i[route_to be_routable].freeze CORRECTABLE_MATCHERS = %i[eq eql equal be].freeze # @!method expect_literal(node) def_node_matcher :expect_literal, <<~PATTERN (send (send nil? :expect $#literal?) #Runners.all ${ (send (send nil? $:be) :== $_) (send nil? $_ $_ ...) } ) PATTERN def on_send(node) expect_literal(node) do |actual, send_node, matcher, expected| next if SKIPPED_MATCHERS.include?(matcher) add_offense(actual) do |corrector| next unless CORRECTABLE_MATCHERS.include?(matcher) next if literal?(expected) corrector.replace(actual, expected.source) if matcher == :be corrector.replace(expected, actual.source) else corrector.replace(send_node, "#{matcher}(#{actual.source})") end end end end private # This is not implemented using a NodePattern because it seems # to not be able to match against an explicit (nil) sexp def literal?(node) node && (simple_literal?(node) || complex_literal?(node)) end def simple_literal?(node) SIMPLE_LITERALS.include?(node.type) end def complex_literal?(node) COMPLEX_LITERALS.include?(node.type) && node.each_child_node.all? { |child_node| literal?(child_node) } end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/expect_change.rb000066400000000000000000000070401512756157400257120ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for consistent style of change matcher. # # Enforces either passing a receiver and message as method arguments, # or a block. # # This cop can be configured using the `EnforcedStyle` option. # # @safety # Autocorrection is unsafe because `method_call` style calls the # receiver *once* and sends the message to it before and after # calling the `expect` block, whereas `block` style calls the # expression *twice*, including the receiver. # # If your receiver is dynamic (e.g., the result of a method call) and # you expect it to be called before and after the `expect` block, # changing from `block` to `method_call` style may break your test. # # [source,ruby] # ---- # expect { run }.to change { my_method.message } # # `my_method` is called before and after `run` # # expect { run }.to change(my_method, :message) # # `my_method` is called once, but `message` is called on it twice # ---- # # @example `EnforcedStyle: method_call` (default) # # bad # expect { run }.to change { Foo.bar } # expect { run }.to change { foo.baz } # # # good # expect { run }.to change(Foo, :bar) # expect { run }.to change(foo, :baz) # # also good when there are arguments or chained method calls # expect { run }.to change { Foo.bar(:count) } # expect { run }.to change { user.reload.name } # # @example `EnforcedStyle: block` # # bad # expect { run }.to change(Foo, :bar) # # # good # expect { run }.to change { Foo.bar } # class ExpectChange < Base extend AutoCorrector include ConfigurableEnforcedStyle MSG_BLOCK = 'Prefer `change(%s, :%s)`.' MSG_CALL = 'Prefer `change { %s.%s }`.' RESTRICT_ON_SEND = %i[change].freeze # @!method expect_change_with_arguments(node) def_node_matcher :expect_change_with_arguments, <<~PATTERN (send nil? :change $_ ({sym str} $_)) PATTERN # @!method expect_change_with_block(node) def_node_matcher :expect_change_with_block, <<~PATTERN (block (send nil? :change) (args) (send ${ (send nil? _) # change { user.name } const # change { User.count } } $_ ) ) PATTERN def on_send(node) return unless style == :block expect_change_with_arguments(node) do |receiver, message| msg = format(MSG_CALL, obj: receiver.source, attr: message) add_offense(node, message: msg) do |corrector| replacement = "change { #{receiver.source}.#{message} }" corrector.replace(node, replacement) end end end def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless style == :method_call expect_change_with_block(node) do |receiver, message| msg = format(MSG_BLOCK, obj: receiver.source, attr: message) add_offense(node, message: msg) do |corrector| replacement = "change(#{receiver.source}, :#{message})" corrector.replace(node, replacement) end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/expect_in_hook.rb000066400000000000000000000021761512756157400261200ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Do not use `expect` in hooks such as `before`. # # @example # # bad # before do # expect(something).to eq 'foo' # end # # # bad # after do # expect_any_instance_of(Something).to receive(:foo) # end # # # good # it do # expect(something).to eq 'foo' # end # class ExpectInHook < Base MSG = 'Do not use `%s` in `%s` hook' # @!method expectation(node) def_node_search :expectation, '(send nil? #Expectations.all ...)' def on_block(node) return unless hook?(node) return if node.body.nil? expectation(node.body) do |expect| add_offense(expect.loc.selector, message: message(expect, node)) end end alias on_numblock on_block private def message(expect, hook) format(MSG, expect: expect.method_name, hook: hook.method_name) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/expect_in_let.rb000066400000000000000000000016721512756157400257440ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Do not use `expect` in let. # # @example # # bad # let(:foo) do # expect(something).to eq 'foo' # end # # # good # it do # expect(something).to eq 'foo' # end # class ExpectInLet < Base MSG = 'Do not use `%s` in let' # @!method expectation(node) def_node_search :expectation, '(send nil? #Expectations.all ...)' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless let?(node) return if node.body.nil? expectation(node.body) do |expect| add_offense(expect.loc.selector, message: message(expect)) end end private def message(expect) format(MSG, expect: expect.method_name) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/expect_output.rb000066400000000000000000000030011512756157400260160ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for opportunities to use `expect { ... }.to output`. # # @example # # bad # $stdout = StringIO.new # my_app.print_report # $stdout = STDOUT # expect($stdout.string).to eq('Hello World') # # # good # expect { my_app.print_report }.to output('Hello World').to_stdout # class ExpectOutput < Base MSG = 'Use `expect { ... }.to output(...).to_%s` ' \ 'instead of mutating $%s.' def on_gvasgn(node) return unless inside_example_scope?(node) name = node.name[1..] return unless name.eql?('stdout') || name.eql?('stderr') add_offense(node.loc.name, message: format(MSG, name: name)) end private # Detect if we are inside the scope of a single example # # We want to encourage using `expect { ... }.to output` so # we only care about situations where you would replace with # an expectation. Therefore, assignments to stderr or stdout # within a `before(:all)` or otherwise outside of an example # don't matter. def inside_example_scope?(node) return false if node.nil? || example_group?(node) return true if example?(node) return RuboCop::RSpec::Hook.new(node).example? if hook?(node) inside_example_scope?(node.parent) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/focus.rb000066400000000000000000000060331512756157400242350ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks if examples are focused. # # This cop does not support autocorrection in some cases. # # @example # # bad # describe MyClass, focus: true do # end # # describe MyClass, :focus do # end # # fdescribe MyClass do # end # # # good # describe MyClass do # end # # # bad # fdescribe 'test' do; end # # # good # describe 'test' do; end # # # bad # shared_examples 'test', focus: true do; end # # # good # shared_examples 'test' do; end # # # bad # shared_context 'test', focus: true do; end # # # good # shared_context 'test' do; end # # # bad (does not support autocorrection) # focus 'test' do; end # class Focus < Base extend AutoCorrector include RangeHelp MSG = 'Focused spec found.' # @!method focusable_selector?(node) def_node_matcher :focusable_selector?, <<~PATTERN { #ExampleGroups.regular #ExampleGroups.skipped #Examples.regular #Examples.skipped #Examples.pending #SharedGroups.all } PATTERN # @!method metadata(node) def_node_matcher :metadata, <<~PATTERN {(send #rspec? #focusable_selector? <$(sym :focus) ...>) (send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))} PATTERN # @!method focused_block?(node) def_node_matcher :focused_block?, <<~PATTERN (send #rspec? {#ExampleGroups.focused #Examples.focused} ...) PATTERN def on_send(node) return if node.chained? || node.each_ancestor(:any_def).any? if focused_block?(node) on_focused_block(node) else metadata(node) do |focus| on_metadata(focus) end end end private def on_focused_block(node) add_offense(node) do |corrector| correct_send(corrector, node) end end def on_metadata(node) add_offense(node) do |corrector| corrector.remove(with_surrounding(node)) end end def with_surrounding(focus) range_with_space = range_with_surrounding_space(focus.source_range, side: :left) range_with_surrounding_comma(range_with_space, :left) end def correct_send(corrector, focus) range = focus.loc.selector unfocused = focus.method_name.to_s.sub(/^f/, '') unless Examples.regular(unfocused) || ExampleGroups.regular(unfocused) return end corrector.replace(range, range.source.sub(focus.method_name.to_s, unfocused)) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/hook_argument.rb000066400000000000000000000065571512756157400257730ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks the arguments passed to `before`, `around`, and `after`. # # This cop checks for consistent style when specifying RSpec # hooks which run for each example. There are three supported # styles: "implicit", "each", and "example." All styles have # the same behavior. # # @example `EnforcedStyle: implicit` (default) # # bad # before(:each) do # # ... # end # # # bad # before(:example) do # # ... # end # # # good # before do # # ... # end # # @example `EnforcedStyle: each` # # bad # before(:example) do # # ... # end # # # bad # before do # # ... # end # # # good # before(:each) do # # ... # end # # @example `EnforcedStyle: example` # # bad # before(:each) do # # ... # end # # # bad # before do # # ... # end # # # good # before(:example) do # # ... # end # class HookArgument < Base extend AutoCorrector include ConfigurableEnforcedStyle IMPLICIT_MSG = 'Omit the default `%p` argument for RSpec hooks.' EXPLICIT_MSG = 'Use `%p` for RSpec hooks.' # @!method scoped_hook(node) def_node_matcher :scoped_hook, <<~PATTERN (any_block $(send _ #Hooks.all (sym ${:each :example})) ...) PATTERN # @!method unscoped_hook(node) def_node_matcher :unscoped_hook, <<~PATTERN (any_block $(send _ #Hooks.all) ...) PATTERN def on_block(node) hook(node) do |method_send, scope_name| return correct_style_detected if scope_name.equal?(style) return check_implicit(method_send) unless scope_name style_detected(scope_name) msg = explicit_message(scope_name) add_offense(method_send, message: msg) do |corrector| autocorrect(corrector, node, method_send) end end end alias on_numblock on_block private def autocorrect(corrector, _node, method_send) scope = implicit_style? ? '' : "(#{style.inspect})" corrector.replace( LocationHelp.arguments_with_whitespace(method_send), scope ) end def check_implicit(method_send) style_detected(:implicit) return if implicit_style? msg = explicit_message(nil) add_offense(method_send.loc.selector, message: msg) do |corrector| scope = "(#{style.inspect})" corrector.replace( LocationHelp.arguments_with_whitespace(method_send), scope ) end end def explicit_message(scope) if implicit_style? format(IMPLICIT_MSG, scope: scope) else format(EXPLICIT_MSG, scope: style) end end def implicit_style? style.equal?(:implicit) end def hook(node, &block) scoped_hook(node, &block) || unscoped_hook(node, &block) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/hooks_before_examples.rb000066400000000000000000000040211512756157400274540ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for before/around/after hooks that come after an example. # # @example # # bad # it 'checks what foo does' do # expect(foo).to be # end # # before { prepare } # after { clean_up } # # # good # before { prepare } # after { clean_up } # # it 'checks what foo does' do # expect(foo).to be # end # class HooksBeforeExamples < Base extend AutoCorrector MSG = 'Move `%s` above the examples in the group.' # @!method example_or_group?(node) def_node_matcher :example_or_group?, <<~PATTERN { (any_block { (send #rspec? #ExampleGroups.all ...) (send nil? #Examples.all ...) } ...) (send nil? #Includes.examples ...) } PATTERN def on_block(node) return unless example_group_with_body?(node) check_hooks(node.body) if multiline_block?(node.body) end alias on_numblock on_block private def multiline_block?(block) block.begin_type? end def check_hooks(node) first_example = find_first_example(node) return unless first_example first_example.right_siblings.each do |sibling| next unless hook?(sibling) msg = format(MSG, hook: sibling.method_name) add_offense(sibling, message: msg) do |corrector| autocorrect(corrector, sibling, first_example) end end end def find_first_example(node) node.children.find { |sibling| example_or_group?(sibling) } end def autocorrect(corrector, node, first_example) RuboCop::RSpec::Corrector::MoveNode.new( node, corrector, processed_source ).move_before(first_example) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/identical_equality_assertion.rb000066400000000000000000000017571512756157400310660ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for equality assertions with identical expressions on both sides. # # @example # # bad # expect(foo.bar).to eq(foo.bar) # expect(foo.bar).to eql(foo.bar) # # # good # expect(foo.bar).to eq(2) # expect(foo.bar).to eql(2) # class IdenticalEqualityAssertion < Base MSG = 'Identical expressions on both sides of the equality ' \ 'may indicate a flawed test.' RESTRICT_ON_SEND = %i[to].freeze # @!method equality_check?(node) def_node_matcher :equality_check?, <<~PATTERN (send (send nil? :expect $_) :to {(send nil? {:eql :eq :be} $_) (send (send nil? :be) :== $_)}) PATTERN def on_send(node) equality_check?(node) do |left, right| add_offense(node) if left == right end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/implicit_block_expectation.rb000066400000000000000000000037001512756157400305030ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that implicit block expectation syntax is not used. # # Prefer using explicit block expectations. # # @example # # bad # subject { -> { do_something } } # it { is_expected.to change(something).to(new_value) } # # # good # it 'changes something to a new value' do # expect { do_something }.to change(something).to(new_value) # end # class ImplicitBlockExpectation < Base MSG = 'Avoid implicit block expectations.' RESTRICT_ON_SEND = %i[is_expected should should_not].freeze # @!method lambda?(node) def_node_matcher :lambda?, <<~PATTERN { (send (const nil? :Proc) :new) (send nil? {:proc :lambda}) } PATTERN # @!method lambda_subject?(node) def_node_matcher :lambda_subject?, '(block #lambda? ...)' # @!method implicit_expect(node) def_node_matcher :implicit_expect, <<~PATTERN $(send nil? {:is_expected :should :should_not} ...) PATTERN def on_send(node) implicit_expect(node) do |implicit_expect| subject = nearest_subject(implicit_expect) add_offense(implicit_expect) if lambda_subject?(subject&.body) end end private def nearest_subject(node) node .each_ancestor(:block) .lazy .select { |block_node| multi_statement_example_group?(block_node) } .map { |block_node| find_subject(block_node) } .find(&:itself) end def multi_statement_example_group?(node) example_group_with_body?(node) && node.body.begin_type? end def find_subject(block_node) block_node.body.child_nodes.find { |send_node| subject?(send_node) } end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/implicit_expect.rb000066400000000000000000000053151512756157400263020ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that a consistent implicit expectation style is used. # # This cop can be configured using the `EnforcedStyle` option # and supports the `--auto-gen-config` flag. # # @example `EnforcedStyle: is_expected` (default) # # bad # it { should be_truthy } # # # good # it { is_expected.to be_truthy } # # @example `EnforcedStyle: should` # # bad # it { is_expected.to be_truthy } # # # good # it { should be_truthy } # class ImplicitExpect < Base extend AutoCorrector include ConfigurableEnforcedStyle MSG = 'Prefer `%s` over `%s`.' RESTRICT_ON_SEND = Runners.all + %i[should should_not] # @!method implicit_expect(node) def_node_matcher :implicit_expect, <<~PATTERN { (send nil? ${:should :should_not} ...) (send (send nil? $:is_expected) #Runners.all ...) } PATTERN alternatives = { 'is_expected.to' => 'should', 'is_expected.not_to' => 'should_not', 'is_expected.to_not' => 'should_not' } ENFORCED_REPLACEMENTS = alternatives.merge(alternatives.invert).freeze def on_send(node) return unless (source_range = offending_expect(node)) expectation_source = source_range.source if expectation_source.start_with?(style.to_s) correct_style_detected else opposite_style_detected msg = offense_message(expectation_source) add_offense(source_range, message: msg) do |corrector| replacement = replacement_source(expectation_source) corrector.replace(source_range, replacement) end end end private def offending_expect(node) case implicit_expect(node) when :is_expected range_for_is_expected(node.loc) when :should, :should_not node.loc.selector end end def range_for_is_expected(source_map) Parser::Source::Range.new( source_map.expression.source_buffer, source_map.expression.begin_pos, source_map.selector.end_pos ) end def offense_message(offending_source) format( MSG, good: replacement_source(offending_source), bad: offending_source ) end def replacement_source(offending_source) ENFORCED_REPLACEMENTS.fetch(offending_source) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/implicit_subject.rb000066400000000000000000000106361512756157400264530ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for usage of implicit subject (`is_expected` / `should`). # # This cop can be configured using the `EnforcedStyle` option # # @example `EnforcedStyle: single_line_only` (default) # # bad # it do # is_expected.to be_truthy # end # # # good # it { is_expected.to be_truthy } # it do # expect(subject).to be_truthy # end # # @example `EnforcedStyle: single_statement_only` # # bad # it do # foo = 1 # is_expected.to be_truthy # end # # # good # it do # foo = 1 # expect(subject).to be_truthy # end # it do # is_expected.to be_truthy # end # # @example `EnforcedStyle: disallow` # # bad # it { is_expected.to be_truthy } # # # good # it { expect(subject).to be_truthy } # # @example `EnforcedStyle: require_implicit` # # bad # it { expect(subject).to be_truthy } # # # good # it { is_expected.to be_truthy } # # # bad # it do # expect(subject).to be_truthy # end # # # good # it do # is_expected.to be_truthy # end # # # good # it { expect(named_subject).to be_truthy } # class ImplicitSubject < Base extend AutoCorrector include ConfigurableEnforcedStyle MSG_REQUIRE_EXPLICIT = "Don't use implicit subject." MSG_REQUIRE_IMPLICIT = "Don't use explicit subject." RESTRICT_ON_SEND = %i[ expect is_expected should should_not ].freeze # @!method explicit_unnamed_subject?(node) def_node_matcher :explicit_unnamed_subject?, <<~PATTERN (send nil? :expect (send nil? :subject)) PATTERN # @!method implicit_subject?(node) def_node_matcher :implicit_subject?, <<~PATTERN (send nil? {:should :should_not :is_expected} ...) PATTERN def on_send(node) return unless invalid?(node) add_offense(node) do |corrector| autocorrect(corrector, node) end end private def autocorrect(corrector, node) case node.method_name when :expect corrector.replace(node, 'is_expected') when :is_expected corrector.replace(node.location.selector, 'expect(subject)') when :should corrector.replace(node.location.selector, 'expect(subject).to') when :should_not corrector.replace(node.location.selector, 'expect(subject).not_to') else # :nocov: :noop # :nocov: end end def message(_node) case style when :require_implicit MSG_REQUIRE_IMPLICIT else MSG_REQUIRE_EXPLICIT end end def invalid?(node) case style when :require_implicit explicit_unnamed_subject?(node) when :disallow implicit_subject_in_non_its?(node) when :single_line_only implicit_subject_in_non_its_and_non_single_line?(node) when :single_statement_only implicit_subject_in_non_its_and_non_single_statement?(node) else # :nocov: :noop # :nocov: end end def implicit_subject_in_non_its?(node) implicit_subject?(node) && !its?(node) end def implicit_subject_in_non_its_and_non_single_line?(node) implicit_subject_in_non_its?(node) && !single_line?(node) end def implicit_subject_in_non_its_and_non_single_statement?(node) implicit_subject_in_non_its?(node) && !single_statement?(node) end def its?(node) example_of(node)&.method?(:its) end def single_line?(node) example_of(node)&.single_line? end def single_statement?(node) !example_of(node)&.body&.begin_type? end def example_of(node) node.each_ancestor.find do |ancestor| example?(ancestor) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/include_examples.rb000066400000000000000000000056551512756157400264500ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for usage of `include_examples`. # # `include_examples`, unlike `it_behaves_like`, does not create its # own context. As such, using `subject`, `let`, `before`/`after`, etc. # within shared examples included with `include_examples` can have # unexpected behavior and side effects. # # Prefer using `it_behaves_like` instead. # # @safety # `include_examples` and `it_behaves_like` have different scoping # behaviors. # Changing `include_examples` to `it_behaves_like` creates a new # context, altering setup dependencies, which can lead to unexpected # test failures. # Specifically, the scope of hooks (`before`, `after`, `around`) # changes, which may prevent expected setup from being inherited # correctly. # # Additionally, `let` and `subject` are affected by scoping rules. # When `include_examples` is used, `let` and `subject` defined within # `shared_examples` are evaluated in the caller's context, allowing # access to their values. # In contrast, `it_behaves_like` creates a new context, preventing # access to `let` or `subject` values from the caller's context. # # [source,ruby] # ---- # shared_examples "mock behavior" do # before do # allow(service).to receive(:call).and_return("mocked response") # end # # it "returns mocked response" do # expect(service.call).to eq "mocked response" # end # end # # context "working example with include_examples" do # let(:service) { double(:service) } # # include_examples "mock behavior" # # it "uses the mocked service" do # expect(service.call).to eq "mocked response" # Passes # end # end # # context "broken example with it_behaves_like" do # let(:service) { double(:service) } # # it_behaves_like "mock behavior" # # it "unexpectedly does not use the mocked service" do # # Fails because `it_behaves_like` does not apply the mock setup # expect(service.call).to eq "mocked response" # end # end # ---- # # @example # # bad # include_examples 'examples' # # # good # it_behaves_like 'examples' # class IncludeExamples < Base extend AutoCorrector MSG = 'Prefer `it_behaves_like` over `include_examples`.' RESTRICT_ON_SEND = %i[include_examples].freeze def on_send(node) selector = node.loc.selector add_offense(selector) do |corrector| corrector.replace(selector, 'it_behaves_like') end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/indexed_let.rb000066400000000000000000000067661512756157400254170ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Do not set up test data using indexes (e.g., `item_1`, `item_2`). # # It makes reading the test harder because it's not clear what exactly # is tested by this particular example. # # The configurable options `AllowedIdentifiers` and `AllowedPatterns` # will also read those set in `Naming/VariableNumber`. # # @example `Max: 1 (default)` # # bad # let(:item_1) { create(:item) } # let(:item_2) { create(:item) } # # let(:item1) { create(:item) } # let(:item2) { create(:item) } # # # good # # let(:visible_item) { create(:item, visible: true) } # let(:invisible_item) { create(:item, visible: false) } # # @example `Max: 2` # # bad # let(:item_1) { create(:item) } # let(:item_2) { create(:item) } # let(:item_3) { create(:item) } # # # good # let(:item_1) { create(:item) } # let(:item_2) { create(:item) } # # @example `AllowedIdentifiers: ['item_1', 'item_2']` # # good # let(:item_1) { create(:item) } # let(:item_2) { create(:item) } # # @example `AllowedPatterns: ['item']` # # good # let(:item_1) { create(:item) } # let(:item_2) { create(:item) } # class IndexedLet < Base include AllowedIdentifiers include AllowedPattern MSG = 'This `let` statement uses `%s` in its name. ' \ 'Please give it a meaningful name.' # @!method let_name(node) def_node_matcher :let_name, <<~PATTERN { (block (send nil? #Helpers.all ({str sym} $_) ...) ...) (send nil? #Helpers.all ({str sym} $_) block_pass) } PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless spec_group?(node) children = node.body&.child_nodes return unless children filter_indexed_lets(children).each do |let_node| index = let_name(let_node)[INDEX_REGEX] add_offense(let_node, message: format(MSG, index: index)) end end private SUFFIX_INDEX_REGEX = /_?\d+$/.freeze private_constant :SUFFIX_INDEX_REGEX INDEX_REGEX = /\d+/.freeze private_constant :INDEX_REGEX def filter_indexed_lets(candidates) candidates .filter { |node| indexed_let?(node) } .group_by { |node| let_name_stripped_index(node) } .values .filter { |lets| lets.length > cop_config['Max'] } .flatten end def indexed_let?(node) let?(node) && SUFFIX_INDEX_REGEX.match?(let_name(node)) && !allowed_identifier?(let_name(node).to_s) && !matches_allowed_pattern?(let_name(node).to_s) end def let_name_stripped_index(node) let_name(node).to_s.gsub(INDEX_REGEX, '') end def cop_config_patterns_values Array(config.for_cop('Naming/VariableNumber') .fetch('AllowedPatterns', [])) + Array(cop_config.fetch('AllowedPatterns', [])) end def allowed_identifiers Array(config.for_cop('Naming/VariableNumber') .fetch('AllowedIdentifiers', [])) + Array(cop_config.fetch('AllowedIdentifiers', [])) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/instance_spy.rb000066400000000000000000000036151512756157400256200ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for `instance_double` used with `have_received`. # # @example # # bad # it do # foo = instance_double(Foo).as_null_object # expect(foo).to have_received(:bar) # end # # # good # it do # foo = instance_spy(Foo) # expect(foo).to have_received(:bar) # end # class InstanceSpy < Base extend AutoCorrector MSG = 'Use `instance_spy` when you check your double ' \ 'with `have_received`.' # @!method null_double(node) def_node_search :null_double, <<~PATTERN (lvasgn $_ (send $(send nil? :instance_double ...) :as_null_object)) PATTERN # @!method have_received_usage(node) def_node_search :have_received_usage, <<~PATTERN (send (send nil? :expect (lvar $_)) :to (send nil? :have_received ...) ...) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) null_double(node) do |var, receiver| have_received_usage(node) do |expected| next if expected != var add_offense(receiver) do |corrector| autocorrect(corrector, receiver) end end end end private def autocorrect(corrector, node) replacement = 'instance_spy' corrector.replace(node.loc.selector, replacement) double_source_map = node.parent.loc as_null_object_range = double_source_map .dot .join(double_source_map.selector) corrector.remove(as_null_object_range) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/instance_variable.rb000066400000000000000000000050161512756157400265670ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for instance variable usage in specs. # # This cop can be configured with the option `AssignmentOnly` which # will configure the cop to only register offenses on instance # variable usage if the instance variable is also assigned within # the spec # # @example # # bad # describe MyClass do # before { @foo = [] } # it { expect(@foo).to be_empty } # end # # # good # describe MyClass do # let(:foo) { [] } # it { expect(foo).to be_empty } # end # # @example with AssignmentOnly configuration # # rubocop.yml # # RSpec/InstanceVariable: # # AssignmentOnly: true # # # bad # describe MyClass do # before { @foo = [] } # it { expect(@foo).to be_empty } # end # # # allowed # describe MyClass do # it { expect(@foo).to be_empty } # end # # # good # describe MyClass do # let(:foo) { [] } # it { expect(foo).to be_empty } # end # class InstanceVariable < Base include TopLevelGroup MSG = 'Avoid instance variables - use let, ' \ 'a method call, or a local variable (if possible).' # @!method dynamic_class?(node) def_node_matcher :dynamic_class?, <<~PATTERN (block (send (const nil? :Class) :new ...) ...) PATTERN # @!method custom_matcher?(node) def_node_matcher :custom_matcher?, <<~PATTERN (block { (send nil? :matcher sym) (send (const (const nil? :RSpec) :Matchers) :define sym) } ...) PATTERN # @!method ivar_usage(node) def_node_search :ivar_usage, '$(ivar $_)' # @!method ivar_assigned?(node) def_node_search :ivar_assigned?, '(ivasgn % ...)' def on_top_level_group(node) ivar_usage(node) do |ivar, name| next if valid_usage?(ivar) next if assignment_only? && !ivar_assigned?(node, name) add_offense(ivar) end end private def valid_usage?(node) node.each_ancestor(:block).any? do |block| dynamic_class?(block) || custom_matcher?(block) end end def assignment_only? cop_config['AssignmentOnly'] end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/is_expected_specify.rb000066400000000000000000000022211512756157400271270ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check for `specify` with `is_expected` and one-liner expectations. # # @example # # bad # specify { is_expected.to be_truthy } # # # good # it { is_expected.to be_truthy } # # # good # specify do # # ... # end # specify { expect(sqrt(4)).to eq(2) } # class IsExpectedSpecify < Base extend AutoCorrector RESTRICT_ON_SEND = %i[specify].freeze IS_EXPECTED_METHODS = ::Set[:is_expected, :are_expected].freeze MSG = 'Use `it` instead of `specify`.' # @!method offense?(node) def_node_matcher :offense?, <<~PATTERN (block (send _ :specify) _ (send (send _ IS_EXPECTED_METHODS) ...)) PATTERN def on_send(node) block_node = node.parent return unless block_node&.single_line? && offense?(block_node) selector = node.loc.selector add_offense(selector) do |corrector| corrector.replace(selector, 'it') end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/it_behaves_like.rb000066400000000000000000000024651512756157400262400ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that only one `it_behaves_like` style is used. # # @example `EnforcedStyle: it_behaves_like` (default) # # bad # it_should_behave_like 'a foo' # # # good # it_behaves_like 'a foo' # # @example `EnforcedStyle: it_should_behave_like` # # bad # it_behaves_like 'a foo' # # # good # it_should_behave_like 'a foo' # class ItBehavesLike < Base extend AutoCorrector include ConfigurableEnforcedStyle MSG = 'Prefer `%s` over `%s` when including ' \ 'examples in a nested context.' RESTRICT_ON_SEND = %i[it_behaves_like it_should_behave_like].freeze # @!method example_inclusion_offense(node) def_node_matcher :example_inclusion_offense, '(send _ % ...)' def on_send(node) example_inclusion_offense(node, alternative_style) do add_offense(node) do |corrector| corrector.replace(node.loc.selector, style.to_s) end end end private def message(_node) format(MSG, replacement: style, original: alternative_style) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/iterated_expectation.rb000066400000000000000000000050121512756157400273160ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that `all` matcher is used instead of iterating over an array. # # @example # # bad # it 'validates users' do # [user1, user2, user3].each { |user| expect(user).to be_valid } # end # # # good # it 'validates users' do # expect([user1, user2, user3]).to all(be_valid) # end # class IteratedExpectation < Base extend AutoCorrector MSG = 'Prefer using the `all` matcher instead ' \ 'of iterating over an array.' # @!method each?(node) def_node_matcher :each?, <<~PATTERN (block (send ... :each) (args (arg $_)) (...) ) PATTERN # @!method each_numblock?(node) def_node_matcher :each_numblock?, <<~PATTERN (numblock (send ... :each) _ (...) ) PATTERN # @!method expectation?(node) def_node_matcher :expectation?, <<~PATTERN (send (send nil? :expect (lvar %)) :to ...) PATTERN def on_block(node) each?(node) do |arg| check_offense(node, arg) end end def on_numblock(node) each_numblock?(node) do check_offense(node, :_1) end end private def check_offense(node, argument) if single_expectation?(node.body, argument) add_offense(node.send_node) do |corrector| next unless node.body.arguments.one? next if uses_argument_in_matcher?(node, argument) corrector.replace(node, single_expectation_replacement(node)) end elsif only_expectations?(node.body, argument) add_offense(node.send_node) end end def single_expectation_replacement(node) collection = node.receiver.source matcher = node.body.first_argument.source "expect(#{collection}).to all(#{matcher})" end def uses_argument_in_matcher?(node, argument) node.body.first_argument.each_descendant.any?(s(:lvar, argument)) end def single_expectation?(body, arg) expectation?(body, arg) end def only_expectations?(body, arg) return false unless body.each_child_node.any? body.each_child_node.all? { |child| expectation?(child, arg) } end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/leading_subject.rb000066400000000000000000000043541512756157400262440ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Enforce that subject is the first definition in the test. # # @example # # bad # let(:params) { blah } # subject { described_class.new(params) } # # before { do_something } # subject { described_class.new(params) } # # it { expect_something } # subject { described_class.new(params) } # it { expect_something_else } # # # # good # subject { described_class.new(params) } # let(:params) { blah } # # # good # subject { described_class.new(params) } # before { do_something } # # # good # subject { described_class.new(params) } # it { expect_something } # it { expect_something_else } # class LeadingSubject < Base extend AutoCorrector include InsideExampleGroup MSG = 'Declare `subject` above any other `%s` declarations.' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless subject?(node) return unless inside_example_group?(node) check_previous_nodes(node) end private def check_previous_nodes(node) offending_node(node) do |offender| msg = format(MSG, offending: offender.method_name) add_offense(node, message: msg) do |corrector| autocorrect(corrector, node, offender) end end end def offending_node(node) parent(node).each_child_node.find do |sibling| break if sibling.equal?(node) yield sibling if offending?(sibling) end end def parent(node) node.each_ancestor(:block).first.body end def autocorrect(corrector, node, sibling) RuboCop::RSpec::Corrector::MoveNode.new( node, corrector, processed_source ).move_before(sibling) end def offending?(node) let?(node) || hook?(node) || example?(node) || spec_group?(node) || include?(node) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/leaky_constant_declaration.rb000066400000000000000000000077631512756157400305140ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that no class, module, or constant is declared. # # Constants, including classes and modules, when declared in a block # scope, are defined in global namespace, and leak between examples. # # If several examples may define a `DummyClass`, instead of being a # blank slate class as it will be in the first example, subsequent # examples will be reopening it and modifying its behavior in # unpredictable ways. # Even worse when a class that exists in the codebase is reopened. # # Anonymous classes are fine, since they don't result in global # namespace name clashes. # # @see https://rspec.info/features/3-12/rspec-mocks/mutating-constants # # @example Constants leak between examples # # bad # describe SomeClass do # OtherClass = Struct.new # CONSTANT_HERE = 'I leak into global namespace' # end # # # good # describe SomeClass do # before do # stub_const('OtherClass', Struct.new) # stub_const('CONSTANT_HERE', 'I only exist during this example') # end # end # # @example # # bad # describe SomeClass do # class FooClass < described_class # def double_that # some_base_method * 2 # end # end # # it { expect(FooClass.new.double_that).to eq(4) } # end # # # good - anonymous class, no constant needs to be defined # describe SomeClass do # let(:foo_class) do # Class.new(described_class) do # def double_that # some_base_method * 2 # end # end # end # # it { expect(foo_class.new.double_that).to eq(4) } # end # # # good - constant is stubbed # describe SomeClass do # before do # foo_class = Class.new(described_class) do # def do_something # end # end # stub_const('FooClass', foo_class) # end # # it { expect(FooClass.new.double_that).to eq(4) } # end # # @example # # bad # describe SomeClass do # module SomeModule # class SomeClass # def do_something # end # end # end # end # # # good # describe SomeClass do # before do # foo_class = Class.new(described_class) do # def do_something # end # end # stub_const('SomeModule::SomeClass', foo_class) # end # end class LeakyConstantDeclaration < Base MSG_CONST = 'Stub constant instead of declaring explicitly.' MSG_CLASS = 'Stub class constant instead of declaring explicitly.' MSG_MODULE = 'Stub module constant instead of declaring explicitly.' def on_casgn(node) return unless inside_describe_block?(node) return if explicit_namespace?(node.namespace) add_offense(node, message: MSG_CONST) end def on_class(node) return unless inside_describe_block?(node) return if explicit_namespace?(node.identifier.namespace) add_offense(node, message: MSG_CLASS) end def on_module(node) return unless inside_describe_block?(node) return if explicit_namespace?(node.identifier.namespace) add_offense(node, message: MSG_MODULE) end private def inside_describe_block?(node) node.each_ancestor(:block).any? { |ancestor| spec_group?(ancestor) } end def explicit_namespace?(namespace) !namespace.nil? end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/leaky_local_variable.rb000066400000000000000000000107531512756157400272460ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for local variables from outer scopes used inside examples. # # Local variables assigned outside an example but used within it act # as shared state, which can make tests non-deterministic. # # @example # # bad - outside variable used in a hook # user = create(:user) # # before { user.update(admin: true) } # # # good # let(:user) { create(:user) } # # before { user.update(admin: true) } # # # bad - outside variable used in an example # user = create(:user) # # it 'is persisted' do # expect(user).to be_persisted # end # # # good # let(:user) { create(:user) } # # it 'is persisted' do # expect(user).to be_persisted # end # # # also good - assigning the variable within the example # it 'is persisted' do # user = create(:user) # # expect(user).to be_persisted # end # # # bad - outside variable passed to included examples # attrs = ['foo', 'bar'] # # it_behaves_like 'some examples', attrs # # # good # it_behaves_like 'some examples' do # let(:attrs) { ['foo', 'bar'] } # end # # # good - when variable is used only as example description # attribute = 'foo' # # it "#{attribute} is persisted" do # expectations # end # # # good - when variable is used only in example metadata # skip_message = 'not yet implemented' # # it 'does something', skip: skip_message do # expectations # end # # # good - when variable is used only to include other examples # examples = foo ? 'some examples' : 'other examples' # # it_behaves_like examples, another_argument # class LeakyLocalVariable < Base MSG = 'Do not use local variables defined outside of ' \ 'examples inside of them.' # @!method example_method?(node) def_node_matcher :example_method?, <<~PATTERN (send nil? #Examples.all _) PATTERN # @!method includes_method?(node) def_node_matcher :includes_method?, <<~PATTERN (send nil? #Includes.all ...) PATTERN def self.joining_forces VariableForce end def after_leaving_scope(scope, _variable_table) scope.variables.each_value { |variable| check_references(variable) } end private def check_references(variable) variable.assignments.each do |assignment| next if part_of_example_scope?(assignment.node) assignment.references.each do |reference| next unless inside_describe_block?(reference) next unless part_of_example_scope?(reference) next if allowed_reference?(reference) add_offense(assignment.node) end end end def allowed_reference?(node) node.each_ancestor.any? do |ancestor| next true if example_method?(ancestor) next true if in_example_arguments?(ancestor, node) if includes_method?(ancestor) next allowed_includes_arguments?(ancestor, node) end false end end def in_example_arguments?(ancestor, node) return false unless ancestor.send_type? return false unless Examples.all(ancestor.method_name) ancestor.arguments.any? do |arg| arg.equal?(node) || arg.each_descendant.any?(node) end end def allowed_includes_arguments?(node, argument) node.arguments[1..].all? do |argument_node| next true if argument_node.type?(:dstr, :dsym) argument_node != argument && argument_node.each_descendant.none?(argument) end end def part_of_example_scope?(node) node.each_ancestor.any? { |ancestor| example_scope?(ancestor) } end def example_scope?(node) subject?(node) || let?(node) || hook?(node) || example?(node) || include?(node) end def inside_describe_block?(node) node.each_ancestor(:block).any? { |ancestor| spec_group?(ancestor) } end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/let_before_examples.rb000066400000000000000000000052001512756157400271150ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for `let` definitions that come after an example. # # @example # # bad # let(:foo) { bar } # # it 'checks what foo does' do # expect(foo).to be # end # # let(:some) { other } # # it 'checks what some does' do # expect(some).to be # end # # # good # let(:foo) { bar } # let(:some) { other } # # it 'checks what foo does' do # expect(foo).to be # end # # it 'checks what some does' do # expect(some).to be # end class LetBeforeExamples < Base extend AutoCorrector MSG = 'Move `let` before the examples in the group.' # @!method example_or_group?(node) def_node_matcher :example_or_group?, <<~PATTERN { (block (send nil? {#ExampleGroups.all #Examples.all} ...) ...) (send nil? #Includes.examples ...) } PATTERN # @!method include_examples?(node) def_node_matcher :include_examples?, <<~PATTERN { (block (send nil? :include_examples ...) ...) (send nil? :include_examples ...) } PATTERN def self.autocorrect_incompatible_with [RSpec::ScatteredLet] end def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group_with_body?(node) check_let_declarations(node.body) if multiline_block?(node.body) end private def example_group_with_include_examples?(body) body.children.any? { |sibling| include_examples?(sibling) } end def multiline_block?(block) block.begin_type? end def check_let_declarations(node) first_example = find_first_example(node) return unless first_example correct = !example_group_with_include_examples?(node) first_example.right_siblings.each do |sibling| next unless let?(sibling) add_offense(sibling) do |corrector| autocorrect(corrector, sibling, first_example) if correct end end end def find_first_example(node) node.children.find { |sibling| example_or_group?(sibling) } end def autocorrect(corrector, node, first_example) RuboCop::RSpec::Corrector::MoveNode.new( node, corrector, processed_source ).move_before(first_example) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/let_setup.rb000066400000000000000000000056531512756157400251310ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks unreferenced `let!` calls being used for test setup. # # @example # # bad # let!(:my_widget) { create(:widget) } # # it 'counts widgets' do # expect(Widget.count).to eq(1) # end # # # good # it 'counts widgets' do # create(:widget) # expect(Widget.count).to eq(1) # end # # # good # before { create(:widget) } # # it 'counts widgets' do # expect(Widget.count).to eq(1) # end # # # good # describe 'a widget' do # let!(:my_widget) { create(:widget) } # context 'when visiting its page' do # let!(:my_widget) { create(:widget, name: 'Special') } # it 'counts widgets' do # expect(Widget.count).to eq(1) # end # end # end # class LetSetup < Base MSG = 'Do not use `let!` to setup objects not referenced in tests.' # @!method example_or_shared_group_or_including?(node) def_node_matcher :example_or_shared_group_or_including?, <<~PATTERN (block { (send #rspec? {#SharedGroups.all #ExampleGroups.all} ...) (send nil? #Includes.all ...) } ...) PATTERN # @!method let_bang(node) def_node_matcher :let_bang, <<~PATTERN { (block $(send nil? :let! {(sym $_) (str $_)}) ...) $(send nil? :let! {(sym $_) (str $_)} block_pass) } PATTERN # @!method method_called?(node) def_node_search :method_called?, '(send nil? %)' def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_or_shared_group_or_including?(node) unused_let_bang(node) do |let| add_offense(let) end end private def unused_let_bang(node) child_let_bang(node) do |method_send, method_name| next if overrides_outer_let_bang?(node, method_name) yield(method_send) unless method_called?(node, method_name.to_sym) end end def child_let_bang(node, &block) RuboCop::RSpec::ExampleGroup.new(node).lets.each do |let| let_bang(let, &block) end end def overrides_outer_let_bang?(node, method_name) node.each_ancestor(:block).any? do |ancestor| next unless example_or_shared_group_or_including?(ancestor) outer_let_bang?(ancestor, method_name) end end def outer_let_bang?(ancestor_node, method_name) RuboCop::RSpec::ExampleGroup.new(ancestor_node).lets.any? do |let| let_bang(let) do |_send, name| name == method_name end end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/match_array.rb000066400000000000000000000032441512756157400254110ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks where `match_array` is used. # # This cop checks for the following: # # - Prefer `contain_exactly` when matching an array with values. # - Prefer `eq` when using `match_array` with an empty array literal. # # @example # # bad # it { is_expected.to match_array([content1, content2]) } # # # good # it { is_expected.to contain_exactly(content1, content2) } # # # good # it { is_expected.to match_array([content] + array) } # # # good # it { is_expected.to match_array(%w(tremble in fear foolish mortals)) } # class MatchArray < Base extend AutoCorrector MSG = 'Prefer `contain_exactly` when matching an array literal.' RESTRICT_ON_SEND = %i[match_array].freeze # @!method match_array_with_empty_array?(node) def_node_matcher :match_array_with_empty_array?, <<~PATTERN (send nil? :match_array (array)) PATTERN def on_send(node) return unless node.first_argument&.array_type? return if match_array_with_empty_array?(node) check_populated_array(node) end private def check_populated_array(node) return if node.first_argument.percent_literal? add_offense(node) do |corrector| array_contents = node.arguments.flat_map(&:to_a) corrector.replace( node, "contain_exactly(#{array_contents.map(&:source).join(', ')})" ) end end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/message_chain.rb000066400000000000000000000013071512756157400257030ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that chains of messages are not being stubbed. # # @example # # bad # allow(foo).to receive_message_chain(:bar, :baz).and_return(42) # # # good # thing = Thing.new(baz: 42) # allow(foo).to receive(:bar).and_return(thing) # class MessageChain < Base MSG = 'Avoid stubbing using `%s`.' RESTRICT_ON_SEND = %i[receive_message_chain stub_chain].freeze def on_send(node) add_offense( node.loc.selector, message: format(MSG, method: node.method_name) ) end end end end end rubocop-rubocop-rspec-a5aeb29/lib/rubocop/cop/rspec/message_expectation.rb000066400000000000000000000031271512756157400271460ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for consistent message expectation style. # # This cop can be configured in your configuration using the # `EnforcedStyle` option and supports `--auto-gen-config`. # # @example `EnforcedStyle: allow` (default) # # # bad # expect(foo).to receive(:bar) # # # good # allow(foo).to receive(:bar) # # @example `EnforcedStyle: expect` # # # bad # allow(foo).to receive(:bar) # # # good # expect(foo).to receive(:bar) # class MessageExpectation < Base include ConfigurableEnforcedStyle MSG = 'Prefer `%