pax_global_header00006660000000000000000000000064143460412760014521gustar00rootroot0000000000000052 comment=f721785ecc551eb9b0c2ad7ca0c74097ee0e35c8 rubocop-rspec-2.16.0/000077500000000000000000000000001434604127600143725ustar00rootroot00000000000000rubocop-rspec-2.16.0/.codespellignore000066400000000000000000000000121434604127600175420ustar00rootroot00000000000000xdescribe rubocop-rspec-2.16.0/.git-blame-ignore-revs000066400000000000000000000001631434604127600204720ustar00rootroot00000000000000# .git-blame-ignore-revs # Add mdformat to the workflow in GitHub Actions 4874a5a4a2a58e76d343aaa02279cd93b16f5a30 rubocop-rspec-2.16.0/.gitattributes000066400000000000000000000000311434604127600172570ustar00rootroot00000000000000CHANGELOG.md merge=union rubocop-rspec-2.16.0/.github/000077500000000000000000000000001434604127600157325ustar00rootroot00000000000000rubocop-rspec-2.16.0/.github/CONTRIBUTING.md000066400000000000000000000057731434604127600201770ustar00rootroot00000000000000# 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 ``` ## 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-rspec-2.16.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000022601434604127600215330ustar00rootroot00000000000000**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-rspec-2.16.0/.github/dependabot.yml000066400000000000000000000001661434604127600205650ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: 'github-actions' directory: '/' schedule: interval: 'weekly' rubocop-rspec-2.16.0/.github/workflows/000077500000000000000000000000001434604127600177675ustar00rootroot00000000000000rubocop-rspec-2.16.0/.github/workflows/codespell.yml000066400000000000000000000005011434604127600224600ustar00rootroot00000000000000name: CodeSpell on: - pull_request jobs: codespell: name: CodeSpell runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: CodeSpell uses: codespell-project/actions-codespell@master with: check_filenames: true ignore_words_file: .codespellignore rubocop-rspec-2.16.0/.github/workflows/linting.yml000066400000000000000000000011471434604127600221610ustar00rootroot00000000000000name: Linting on: - pull_request jobs: yamllint: name: Yamllint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Yamllint uses: karancode/yamllint-github-action@master with: yamllint_comment: true env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} mdformat: name: Mdformat runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Mdformat uses: ydah/mdformat-action@main with: number: true env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} rubocop-rspec-2.16.0/.github/workflows/main.yml000066400000000000000000000043461434604127600214450ustar00rootroot00000000000000name: CI on: pull_request: push: branches: - master jobs: confirm_config_and_documentation: runs-on: ubuntu-latest name: Confirm config and documentation steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: "3.1" bundler-cache: true - run: bundle exec rake confirm_config documentation_syntax_check confirm_documentation main: runs-on: ubuntu-latest strategy: matrix: ruby: - "2.6" - "2.7" - "3.0" - "3.1" - ruby-head - jruby-9.3 task: - internal_investigation - spec name: "Ruby ${{ matrix.ruby }}: ${{ matrix.task }}" steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: "${{ matrix.ruby }}" bundler-cache: true - run: bundle exec rake ${{ matrix.task }} edge-rubocop: runs-on: ubuntu-latest strategy: matrix: task: - internal_investigation - spec name: "Edge RuboCop: ${{ matrix.task }}" steps: - uses: actions/checkout@v3 - name: Use latest RuboCop from `master` run: | echo "gem 'rubocop', github: 'rubocop-hq/rubocop'" > Gemfile.local - uses: ruby/setup-ruby@v1 with: ruby-version: "3.1" bundler-cache: true - run: bundle exec rake ${{ matrix.task }} rspec4: runs-on: ubuntu-latest name: RSpec 4 steps: - uses: actions/checkout@v3 - 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-core', branch: '4-0-dev' gem 'rspec-expectations', github: 'rspec/rspec-expectations', branch: '4-0-dev' gem 'rspec-mocks', github: 'rspec/rspec-mocks', branch: '4-0-dev' gem 'rspec-support', github: 'rspec/rspec-support', branch: '4-0-dev' EOF - uses: ruby/setup-ruby@v1 with: ruby-version: "3.1" bundler-cache: true - run: bundle exec rake spec rubocop-rspec-2.16.0/.gitignore000066400000000000000000000002401434604127600163560ustar00rootroot00000000000000# rdoc generated rdoc # yard generated doc .yardoc # bundler .bundle Gemfile.lock Gemfile.local # jeweler generated pkg /vendor .ruby-gemset .ruby-version rubocop-rspec-2.16.0/.rspec000066400000000000000000000000551434604127600155070ustar00rootroot00000000000000--require spec_helper --format documentation rubocop-rspec-2.16.0/.rubocop.yml000066400000000000000000000052601434604127600166470ustar00rootroot00000000000000inherit_from: .rubocop_todo.yml require: - rubocop-performance - rubocop-rake - rubocop-rspec - rubocop/cop/internal_affairs AllCops: DisplayCopNames: true TargetRubyVersion: 2.6 NewCops: disable Exclude: - 'vendor/**/*' - 'spec/fixtures/**/*' - 'tmp/**/*' - 'spec/smoke_tests/**/*.rb' 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 Metrics/BlockLength: Exclude: - rubocop-rspec.gemspec - Rakefile - '**/*.rake' Naming/FileName: Exclude: - lib/rubocop-rspec.rb Naming/InclusiveLanguage: Enabled: true CheckStrings: true FlaggedTerms: auto-correct: Suggestions: - autocorrect auto_correct: Suggestions: - autocorrect behaviour: Suggestions: - behavior offence: Suggestions: - offense 'does not registers': Suggestions: - does not register RSpec: Language: Expectations: - expect_correction - expect_no_offenses - expect_offense RSpec/ExampleLength: CountAsOne: - heredoc Max: 11 RSpec/DescribeClass: Exclude: - spec/project/**/*.rb RSpec/MultipleExpectations: Max: 2 Style/FormatStringToken: Exclude: - spec/rubocop/**/*.rb Style/RequireOrder: Enabled: true # Enable some of RuboCop's pending cops. Layout/LineContinuationSpacing: Enabled: true Layout/LineEndStringConcatenationIndentation: Enabled: true Style/EmptyHeredoc: Enabled: true # Enable our own pending cops. RSpec/BeEq: Enabled: true RSpec/BeNil: Enabled: true RSpec/ChangeByZero: Enabled: true RSpec/ClassCheck: Enabled: true RSpec/DuplicatedMetadata: Enabled: true RSpec/ExcessiveDocstringSpacing: Enabled: true RSpec/IdenticalEqualityAssertion: Enabled: true RSpec/NoExpectationExample: Enabled: true RSpec/PendingWithoutReason: Enabled: true RSpec/SortMetadata: Enabled: true RSpec/SubjectDeclaration: Enabled: true RSpec/VerifiedDoubleReference: Enabled: true rubocop-rspec-2.16.0/.rubocop_todo.yml000066400000000000000000000007351434604127600176760ustar00rootroot00000000000000# This configuration was generated by # `rubocop --auto-gen-config --no-offense-counts --no-auto-gen-timestamp` # using RuboCop version 1.36.0. # 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-rspec-2.16.0/.yamllint000066400000000000000000000003101434604127600162160ustar00rootroot00000000000000extends: 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-rspec-2.16.0/.yardopts000066400000000000000000000001131434604127600162330ustar00rootroot00000000000000--markup markdown --hide-void-return --tag safety:"Cop Safety Information" rubocop-rspec-2.16.0/CHANGELOG.md000066400000000000000000001221031434604127600162020ustar00rootroot00000000000000# Changelog ## Master (Unreleased) ## 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]) [@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 [@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 [@cfabianski]: https://github.com/cfabianski [@clupprich]: https://github.com/clupprich [@composerinteralia]: https://github.com/composerinteralia [@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 [@drowze]: https://github.com/Drowze [@dswij]: https://github.com/dswij [@dvandersluis]: https://github.com/dvandersluis [@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 [@foton]: https://github.com/foton [@francois-ferrandis]: https://github.com/francois-ferrandis [@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 [@hosamaly]: https://github.com/hosamaly [@ignaciovillaverde]: https://github.com/ignaciovillaverde [@jaredbeck]: https://github.com/jaredbeck [@jaredmoody]: https://github.com/jaredmoody [@jeffreyc]: https://github.com/jeffreyc [@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 [@kellysutton]: https://github.com/kellysutton [@koic]: https://github.com/koic [@kuahyeow]: https://github.com/kuahyeow [@lazycoder9]: https://github.com/lazycoder9 [@leoarnold]: https://github.com/leoarnold [@liberatys]: https://github.com/Liberatys [@lokhi]: https://github.com/lokhi [@luke-hill]: https://github.com/luke-hill [@m-yamashita01]: https://github.com/M-Yamashita01 [@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 [@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 [@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 [@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 [@stephannv]: https://github.com/stephannv [@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 [@topalovic]: https://github.com/topalovic [@twalpole]: https://github.com/twalpole [@vzvu3k6k]: https://github.com/vzvu3k6k [@walf443]: https://github.com/walf443 [@ybiquitous]: https://github.com/ybiquitous [@ydah]: https://github.com/ydah [@yevhene]: https://github.com/yevhene [@ypresto]: https://github.com/ypresto [@zdennis]: https://github.com/zdennis [@zverok]: https://github.com/zverok rubocop-rspec-2.16.0/CODE_OF_CONDUCT.md000066400000000000000000000015711434604127600171750ustar00rootroot00000000000000# 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-rspec-2.16.0/Gemfile000066400000000000000000000004461434604127600156710ustar00rootroot00000000000000# frozen_string_literal: true source 'https://rubygems.org' gemspec gem 'bump' gem 'rack' gem 'rake' gem 'rspec', '~> 3.11' gem 'rubocop-performance', '~> 1.7' gem 'rubocop-rake', '~> 0.6' gem 'yard' local_gemfile = 'Gemfile.local' eval_gemfile(local_gemfile) if File.exist?(local_gemfile) rubocop-rspec-2.16.0/MIT-LICENSE.md000066400000000000000000000021101434604127600164170ustar00rootroot00000000000000# 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-rspec-2.16.0/README.md000066400000000000000000000042741434604127600156600ustar00rootroot00000000000000# 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-hq/rubocop-rspec/workflows/CI/badge.svg) RSpec-specific analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop/rubocop). ## Installation Just install the `rubocop-rspec` gem ```bash gem install rubocop-rspec ``` or if you use bundler put this in your `Gemfile` ``` gem 'rubocop-rspec', require: false ``` ### 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 require: rubocop-rspec ``` Alternatively, use the following array notation when specifying multiple extensions. ```yaml require: - rubocop-other-extension - rubocop-rspec ``` Now you can run `rubocop` and it will automatically load the RuboCop RSpec cops together with the standard cops. ### Command line ```bash rubocop --require rubocop-rspec ``` ### Rake task ```ruby RuboCop::RakeTask.new do |task| task.requires << '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/FilePath: 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-rspec-2.16.0/Rakefile000066400000000000000000000035601434604127600160430ustar00rootroot00000000000000# 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' 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' task :internal_investigation do sh('bundle exec rubocop --require rubocop-rspec') end desc 'Build config/default.yml' task :build_config do sh('bin/build_config') 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} Run bin/build_config ERROR end desc 'Confirm documentation is up to date' task confirm_documentation: :generate_cops_documentation do _, _, _, process = Open3.popen3('git diff --exit-code docs/') unless process.value.success? raise 'Please run `rake generate_cops_documentation` ' \ 'and add docs/ to the commit.' 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' cop_name = args.fetch(:cop) do warn "usage: bundle exec rake 'new_cop[Department/Name]'" exit! end generator = RuboCop::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-rspec-2.16.0/bin/000077500000000000000000000000001434604127600151425ustar00rootroot00000000000000rubocop-rspec-2.16.0/bin/build_config000077500000000000000000000024201434604127600175120ustar00rootroot00000000000000#!/usr/bin/env ruby # frozen_string_literal: true $LOAD_PATH.unshift(File.join(__dir__, '..', 'lib')) require 'yard' require 'rubocop-rspec' require 'rubocop/rspec/config_formatter' require 'rubocop/rspec/description_extractor' glob = File.join('lib', 'rubocop', 'cop', 'rspec', '{,capybara,factory_bot,rails}', '*.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 ) rubocop-rspec-2.16.0/config/000077500000000000000000000000001434604127600156375ustar00rootroot00000000000000rubocop-rspec-2.16.0/config/default.yml000066400000000000000000001012311434604127600200040ustar00rootroot00000000000000--- RSpec: Enabled: true StyleGuideBaseURL: https://rspec.rubystyle.guide DocumentationBaseURL: https://docs.rubocop.org/rubocop-rspec Include: &1 - "**/*_spec.rb" - "**/spec/**/*" Language: &2 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 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/BeEq: Description: Check for expectations where `be(...)` can replace `eq(...)`. Enabled: pending 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: pending 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) isn't being used. Enabled: true Exclude: - spec/spec_helper.rb - spec/rails_helper.rb - spec/support/**/*.rb VersionAdded: '1.12' 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: pending 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: pending 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/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 SafeAutoCorrect: false VersionAdded: '1.0' VersionChanged: '1.11' 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: pending 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 SafeAutoCorrect: false VersionAdded: '1.7' VersionChanged: '2.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup RSpec/EmptyHook: Description: Checks for empty before and after hooks. Enabled: true VersionAdded: '1.39' 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/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' 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: pending 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' 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/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/FilePath: Description: Checks that spec file paths are consistent and well-formed. Enabled: true Include: - "**/*_spec*rb*" - "**/spec/**/*" CustomTransform: RuboCop: rubocop RSpec: rspec IgnoreMethods: false SpecSuffixOnly: false VersionAdded: '1.2' VersionChanged: '1.40' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FilePath RSpec/Focus: Description: Checks if examples are focused. Enabled: true VersionAdded: '1.5' VersionChanged: '2.1' 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 VersionAdded: '1.29' 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: pending 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/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/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/LetBeforeExamples: Description: Checks for `let` definitions that come after an example. Enabled: true VersionAdded: '1.16' VersionChanged: '1.22' 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/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/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/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: pending 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/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: pending 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/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/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/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 VersionAdded: '1.14' VersionChanged: '1.39' 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 VersionAdded: '1.10' 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: Enforces use of string to titleize shared examples. Enabled: true VersionAdded: '1.25' 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/SortMetadata: Description: Sort RSpec metadata alphabetically. Enabled: pending VersionAdded: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata 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: pending 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/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: pending SafeAutoCorrect: false EnforcedStyle: constant SupportedStyles: - constant - string VersionAdded: 2.10.0 VersionChanged: '2.12' 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 RSpec/Capybara: Enabled: true Include: *1 Language: *2 RSpec/Capybara/CurrentPathExpectation: Description: Checks that no expectations are set on Capybara's `current_path`. Enabled: true VersionAdded: '1.18' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/CurrentPathExpectation RSpec/Capybara/FeatureMethods: Description: Checks for consistent method usage in feature specs. Enabled: true EnabledMethods: [] VersionAdded: '1.17' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods RSpec/Capybara/NegationMatcher: Description: Enforces use of `have_no_*` or `not_to` for negated expectations. Enabled: pending VersionAdded: '2.14' EnforcedStyle: not_to SupportedStyles: - have_no - not_to Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/NegationMatcher RSpec/Capybara/SpecificActions: Description: Checks for there is a more specific actions offered by Capybara. Enabled: pending VersionAdded: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificActions RSpec/Capybara/SpecificFinders: Description: Checks if there is a more specific finder offered by Capybara. Enabled: pending VersionAdded: '2.13' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificFinders RSpec/Capybara/SpecificMatcher: Description: Checks for there is a more specific matcher offered by Capybara. Enabled: pending VersionAdded: '2.12' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificMatcher RSpec/Capybara/VisibilityMatcher: Description: Checks for boolean visibility in Capybara finders. Enabled: true VersionAdded: '1.39' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/VisibilityMatcher RSpec/FactoryBot: Enabled: true Include: *1 Language: *2 RSpec/FactoryBot/AttributeDefinedStatically: Description: Always declare attribute values as blocks. Enabled: true Include: - spec/factories.rb - spec/factories/**/*.rb - features/support/factories/**/*.rb VersionAdded: '1.28' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/AttributeDefinedStatically RSpec/FactoryBot/ConsistentParenthesesStyle: Description: Use a consistent style for parentheses in factory bot calls. Enabled: pending EnforcedStyle: require_parentheses SupportedStyles: - require_parentheses - omit_parentheses VersionAdded: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/ConsistentParenthesesStyle RSpec/FactoryBot/CreateList: Description: Checks for create_list usage. Enabled: true Include: - "**/*_spec.rb" - "**/spec/**/*" - spec/factories.rb - spec/factories/**/*.rb - features/support/factories/**/*.rb EnforcedStyle: create_list SupportedStyles: - create_list - n_times VersionAdded: '1.25' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/CreateList RSpec/FactoryBot/FactoryClassName: Description: Use string value when setting the class attribute explicitly. Enabled: true Include: - spec/factories.rb - spec/factories/**/*.rb - features/support/factories/**/*.rb VersionAdded: '1.37' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/FactoryClassName RSpec/FactoryBot/FactoryNameStyle: Description: Checks for name style for argument of FactoryBot::Syntax::Methods. Enabled: pending VersionAdded: '2.16' EnforcedStyle: symbol SupportedStyles: - symbol - string Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/FactoryNameStyle RSpec/FactoryBot/SyntaxMethods: Description: Use shorthands from `FactoryBot::Syntax::Methods` in your specs. Enabled: pending SafeAutoCorrect: false VersionAdded: '2.7' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/SyntaxMethods RSpec/Rails: Enabled: true Include: *1 Language: *2 RSpec/Rails/AvoidSetupHook: Description: Checks that tests use RSpec `before` hook over Rails `setup` method. Enabled: pending VersionAdded: '2.4' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/AvoidSetupHook RSpec/Rails/HaveHttpStatus: Description: Checks that tests use `have_http_status` instead of equality matchers. Enabled: pending SafeAutoCorrect: false VersionAdded: '2.12' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus RSpec/Rails/HttpStatus: Description: Enforces use of symbolic or numeric value to describe HTTP status. Enabled: true EnforcedStyle: symbolic SupportedStyles: - numeric - symbolic VersionAdded: '1.23' VersionChanged: '2.0' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HttpStatus RSpec/Rails/InferredSpecType: Description: Identifies redundant spec type. Enabled: pending Safe: false VersionAdded: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/InferredSpecType Inferences: channels: channel controllers: controller features: feature generator: generator helpers: helper jobs: job mailboxes: mailbox mailers: mailer models: model requests: request integration: request api: request routing: routing system: system views: view rubocop-rspec-2.16.0/config/obsoletion.yml000066400000000000000000000006361434604127600205440ustar00rootroot00000000000000# # 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 rubocop-rspec-2.16.0/docs/000077500000000000000000000000001434604127600153225ustar00rootroot00000000000000rubocop-rspec-2.16.0/docs/antora.yml000066400000000000000000000001301434604127600173230ustar00rootroot00000000000000name: rubocop-rspec title: RuboCop RSpec version: '2.16' nav: - modules/ROOT/nav.adoc rubocop-rspec-2.16.0/docs/modules/000077500000000000000000000000001434604127600167725ustar00rootroot00000000000000rubocop-rspec-2.16.0/docs/modules/ROOT/000077500000000000000000000000001434604127600175555ustar00rootroot00000000000000rubocop-rspec-2.16.0/docs/modules/ROOT/nav.adoc000066400000000000000000000007251434604127600211750ustar00rootroot00000000000000* 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:third_party_rspec_syntax_extensions.adoc[RSpec syntax extensions in third-party gems] * xref:development.adoc[Development] * Cops Documentation ** xref:cops_rspec_capybara.adoc[Capybara] ** xref:cops_rspec_factorybot.adoc[FactoryBot] ** xref:cops_rspec_rails.adoc[Rails] ** xref:cops_rspec.adoc[RSpec] rubocop-rspec-2.16.0/docs/modules/ROOT/pages/000077500000000000000000000000001434604127600206545ustar00rootroot00000000000000rubocop-rspec-2.16.0/docs/modules/ROOT/pages/cops.adoc000066400000000000000000000175561434604127600224660ustar00rootroot00000000000000// 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#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#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#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#rspecexpectoutput[RSpec/ExpectOutput] * xref:cops_rspec.adoc#rspecfilepath[RSpec/FilePath] * 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#rspecinstancespy[RSpec/InstanceSpy] * xref:cops_rspec.adoc#rspecinstancevariable[RSpec/InstanceVariable] * 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#rspecletbeforeexamples[RSpec/LetBeforeExamples] * xref:cops_rspec.adoc#rspecletsetup[RSpec/LetSetup] * 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#rspecmissingexamplegroupargument[RSpec/MissingExampleGroupArgument] * 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#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#rspecreceivenever[RSpec/ReceiveNever] * 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#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#rspecsortmetadata[RSpec/SortMetadata] * 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#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] === Department xref:cops_rspec_capybara.adoc[RSpec/Capybara] * xref:cops_rspec_capybara.adoc#rspeccapybara/currentpathexpectation[RSpec/Capybara/CurrentPathExpectation] * xref:cops_rspec_capybara.adoc#rspeccapybara/featuremethods[RSpec/Capybara/FeatureMethods] * xref:cops_rspec_capybara.adoc#rspeccapybara/negationmatcher[RSpec/Capybara/NegationMatcher] * xref:cops_rspec_capybara.adoc#rspeccapybara/specificactions[RSpec/Capybara/SpecificActions] * xref:cops_rspec_capybara.adoc#rspeccapybara/specificfinders[RSpec/Capybara/SpecificFinders] * xref:cops_rspec_capybara.adoc#rspeccapybara/specificmatcher[RSpec/Capybara/SpecificMatcher] * xref:cops_rspec_capybara.adoc#rspeccapybara/visibilitymatcher[RSpec/Capybara/VisibilityMatcher] === Department xref:cops_rspec_factorybot.adoc[RSpec/FactoryBot] * xref:cops_rspec_factorybot.adoc#rspecfactorybot/attributedefinedstatically[RSpec/FactoryBot/AttributeDefinedStatically] * xref:cops_rspec_factorybot.adoc#rspecfactorybot/consistentparenthesesstyle[RSpec/FactoryBot/ConsistentParenthesesStyle] * xref:cops_rspec_factorybot.adoc#rspecfactorybot/createlist[RSpec/FactoryBot/CreateList] * xref:cops_rspec_factorybot.adoc#rspecfactorybot/factoryclassname[RSpec/FactoryBot/FactoryClassName] * xref:cops_rspec_factorybot.adoc#rspecfactorybot/factorynamestyle[RSpec/FactoryBot/FactoryNameStyle] * xref:cops_rspec_factorybot.adoc#rspecfactorybot/syntaxmethods[RSpec/FactoryBot/SyntaxMethods] === Department xref:cops_rspec_rails.adoc[RSpec/Rails] * xref:cops_rspec_rails.adoc#rspecrails/avoidsetuphook[RSpec/Rails/AvoidSetupHook] * xref:cops_rspec_rails.adoc#rspecrails/havehttpstatus[RSpec/Rails/HaveHttpStatus] * xref:cops_rspec_rails.adoc#rspecrails/httpstatus[RSpec/Rails/HttpStatus] * xref:cops_rspec_rails.adoc#rspecrails/inferredspectype[RSpec/Rails/InferredSpecType] // END_COP_LIST rubocop-rspec-2.16.0/docs/modules/ROOT/pages/cops_rspec.adoc000066400000000000000000002436001434604127600236510ustar00rootroot00000000000000= RSpec == RSpec/AlignLeftLetBrace |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | Yes | 1.16 | - |=== Checks that left braces for adjacent single line lets are aligned. === Examples [source,ruby] ---- # bad let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } # good let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignLeftLetBrace == RSpec/AlignRightLetBrace |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | Yes | 1.16 | - |=== Checks that right braces for adjacent single line lets are aligned. === Examples [source,ruby] ---- # bad let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } # good let(:foobar) { blahblah } let(:baz) { bar } let(:a) { b } ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace == 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 [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 * https://rspec.rubystyle.guide/#any_instance_of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AnyInstance == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AroundBlock == 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 [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 * https://rspec.rubystyle.guide/#be-matcher * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be == RSpec/BeEq |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | No | Yes (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 This cop is unsafe because it changes how values are compared. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEq == RSpec/BeEql |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | No | Yes (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 This cop is unsafe because it changes how values are compared. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql == RSpec/BeNil |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 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 ==== `EnforcedStyle: be_nil` (default) [source,ruby] ---- # bad expect(foo).to be(nil) # good expect(foo).to be_nil ---- ==== `EnforcedStyle: be` [source,ruby] ---- # bad expect(foo).to be_nil # good expect(foo).to be(nil) ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `be_nil` | `be`, `be_nil` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil == RSpec/BeforeAfterAll |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.12 | - |=== Check that before/after(:all) isn't being used. === Examples [source,ruby] ---- # bad # # Faster but risk of state leaking between examples # describe MyClass do before(:all) { Widget.create } after(:all) { 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 |=== | Name | Default value | Configurable values | Exclude | `spec/spec_helper.rb`, `spec/rails_helper.rb`, `+spec/support/**/*.rb+` | Array |=== === References * https://rspec.rubystyle.guide/#avoid-hooks-with-context-scope * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll == RSpec/ChangeByZero |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 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 ==== 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 [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 |=== | Name | Default value | Configurable values | NegatedMatcher | `` | |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero == RSpec/ClassCheck |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.13 | - |=== Enforces consistent use of `be_a` or `be_kind_of`. === Examples ==== 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 [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 |=== | Name | Default value | Configurable values | EnforcedStyle | `be_a` | `be_a`, `be_kind_of` |=== === References * https://rubystyle.guide#is-a-vs-kind-of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck == RSpec/ContextMethod |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.36 | - |=== `context` should not be used for specifying methods. === 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 * https://rspec.rubystyle.guide/#example-group-naming * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextMethod == 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. This cop can be customized allowed context description pattern with `AllowedPatterns`. By default, there are no checking by pattern. === Examples ==== `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 [source,ruby] ---- # .rubocop.yml # RSpec/ContextWording: # AllowedPatterns: # - とき$ ---- [source,ruby] ---- # bad context '条件を満たす' do # ... end # good context '条件を満たすとき' do # ... end ---- === Configurable attributes |=== | Name | Default value | Configurable values | Prefixes | `when`, `with`, `without` | Array | AllowedPatterns | `[]` | Array |=== === References * https://rspec.rubystyle.guide/#context-descriptions * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording == 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 ==== `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 |=== | 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeMethod == RSpec/DescribeSymbol |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.15 | - |=== Avoid describing symbols. === Examples [source,ruby] ---- # bad describe :my_method do # ... end # good describe '#my_method' do # ... end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeSymbol == RSpec/DescribedClass |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes (Unsafe) | 1.0 | 1.11 |=== 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` and `SkipBlocks` options. 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. === Examples ==== `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 ---- ==== `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` [source,ruby] ---- # spec/controllers/.rubocop.yml # RSpec/DescribedClass: # SkipBlocks: true # acceptable describe MyConcern do controller(ApplicationController) do include MyConcern end end ---- === Configurable attributes |=== | Name | Default value | Configurable values | SkipBlocks | `false` | Boolean | EnforcedStyle | `described_class` | `described_class`, `explicit` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass == 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 [source,ruby] ---- # bad module MyModule RSpec.describe MyClass do # ... end end # good RSpec.describe MyModule::MyClass do # ... end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping == RSpec/Dialect |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Disabled | Yes | Yes | 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 By default all of the RSpec methods and aliases are allowed. By setting a config like: RSpec/Dialect: PreferredMethods: context: describe You can expect the following behavior: === Examples [source,ruby] ---- # bad context 'display name presence' do # ... end # good describe 'display name presence' do # ... end ---- === Configurable attributes |=== | Name | Default value | Configurable values | PreferredMethods | `{}` | |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Dialect == RSpec/DuplicatedMetadata |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.16 | - |=== Avoid duplicated metadata. === Examples [source,ruby] ---- # bad describe 'Something', :a, :a # good describe 'Something', :a ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DuplicatedMetadata == RSpec/EmptyExampleGroup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes (Unsafe) | 1.7 | 2.13 |=== Checks if an example group does not include any tests. === Examples ==== 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup == RSpec/EmptyHook |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.39 | - |=== Checks for empty before and after hooks. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyHook == RSpec/EmptyLineAfterExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.36 | - |=== Checks if there is an empty line after example blocks. === 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 [source,ruby] ---- # rubocop.yml # RSpec/EmptyLineAfterExample: # AllowConsecutiveOneLiners: false # bad RSpec.describe Foo do it { one } it { two } end ---- === Configurable attributes |=== | Name | Default value | Configurable values | AllowConsecutiveOneLiners | `true` | Boolean |=== === References * https://rspec.rubystyle.guide/#empty-lines-around-examples * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExample == RSpec/EmptyLineAfterExampleGroup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.27 | - |=== Checks if there is an empty line after example group blocks. === 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 * https://rspec.rubystyle.guide/#empty-lines-between-describes * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup == RSpec/EmptyLineAfterFinalLet |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.14 | - |=== Checks if there is an empty line after the last let block. === Examples [source,ruby] ---- # bad let(:foo) { bar } let(:something) { other } it { does_something } # good let(:foo) { bar } let(:something) { other } it { does_something } ---- === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet == RSpec/EmptyLineAfterHook |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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 [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 [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 |=== | Name | Default value | Configurable values | AllowConsecutiveOneLiners | `true` | Boolean |=== === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook == RSpec/EmptyLineAfterSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.14 | - |=== Checks if there is an empty line after subject block. === Examples [source,ruby] ---- # bad subject(:obj) { described_class } let(:foo) { bar } # good subject(:obj) { described_class } let(:foo) { bar } ---- === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterSubject == 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 literals you want to fold with `CountAsOne`. Available are: 'array', 'hash', and 'heredoc'. Each literal will be counted as one line regardless of its actual size. === 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'] [source,ruby] ---- it do array = [ # +1 1, 2 ] hash = { # +3 key: 'value' } msg = <<~HEREDOC # +1 Heredoc content. HEREDOC end # 5 points ---- === Configurable attributes |=== | Name | Default value | Configurable values | Max | `5` | Integer | CountAsOne | `[]` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength == 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. 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 ==== `EnforcedStyle: always_allow` (default) [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 } it do result = service.call expect(result).to be(true) end ---- ==== `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` [source,ruby] ---- # bad it { is_expected.to be_good } it do result = service.call expect(result).to be(true) end ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `always_allow` | `always_allow`, `single_line_only`, `disallow` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription == RSpec/ExampleWording |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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. The autocorrect is experimental - use with care! It can be configured with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only). Use the DisallowedExamples setting to prevent unclear or insufficient descriptions. Please note that this config will not be treated as case sensitive. === Examples [source,ruby] ---- # bad it 'should 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) [source,ruby] ---- # bad it 'works' do end # good it 'marks the task as done' do end ---- === Configurable attributes |=== | Name | Default value | Configurable values | CustomTransform | `{"be"=>"is", "BE"=>"IS", "have"=>"has", "HAVE"=>"HAS"}` | | IgnoredWords | `[]` | Array | DisallowedExamples | `works` | Array |=== === References * https://rspec.rubystyle.guide/#should-in-example-docstrings * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording == RSpec/ExcessiveDocstringSpacing |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.5 | - |=== Checks for excessive whitespace in example descriptions. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExcessiveDocstringSpacing == RSpec/ExpectActual |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.7 | - |=== Checks for `expect(...)` calls containing literal values. Autocorrection is performed when the expected is not a literal. === 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 |=== | Name | Default value | Configurable values | Exclude | `+spec/routing/**/*+` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual == RSpec/ExpectChange |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes (Unsafe) | 1.22 | 2.5 |=== Checks for consistent style of change matcher. Enforces either passing object and attribute as arguments to the matcher or passing a block that reads the attribute value. This cop can be configured using the `EnforcedStyle` option. === Examples ==== `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` [source,ruby] ---- # bad expect { run }.to change(Foo, :bar) # good expect { run }.to change { Foo.bar } ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `method_call` | `method_call`, `block` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectOutput == RSpec/FilePath |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.2 | 1.40 |=== Checks that spec file paths are consistent and well-formed. By default, this checks that spec file paths are consistent with the test subject and and enforces that it reflects the described class/module and its optionally called out method. With the configuration option `IgnoreMethods` the called out method will be ignored when determining the enforced path. With the configuration option `CustomTransform` modules or classes can be specified that should not as usual be transformed from CamelCase to snake_case (e.g. 'RuboCop' => 'rubocop' ). With the configuration option `SpecSuffixOnly` test files will only be checked to ensure they end in '_spec.rb'. This option disables checking for consistency in the test subject or test methods. === Examples [source,ruby] ---- # bad whatever_spec.rb # describe MyClass # bad my_class_spec.rb # describe MyClass, '#method' # good my_class_spec.rb # describe MyClass # good my_class_method_spec.rb # describe MyClass, '#method' # good my_class/method_spec.rb # describe MyClass, '#method' ---- ==== when configuration is `IgnoreMethods: true` [source,ruby] ---- # bad whatever_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass, '#method' ---- ==== when configuration is `SpecSuffixOnly: true` [source,ruby] ---- # good whatever_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass, '#method' ---- === Configurable attributes |=== | Name | Default value | Configurable values | Include | `+**/*_spec*rb*+`, `+**/spec/**/*+` | Array | CustomTransform | `{"RuboCop"=>"rubocop", "RSpec"=>"rspec"}` | | IgnoreMethods | `false` | Boolean | SpecSuffixOnly | `false` | Boolean |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FilePath == RSpec/Focus |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.5 | 2.1 |=== Checks if examples are focused. This cop does not support autocorrection in some cases. === 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 fdescribe 'test' do; end # good describe 'test' do; end # bad (does not support autocorrection) focus 'test' do; end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Focus == RSpec/HookArgument |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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 ==== `EnforcedStyle: implicit` (default) [source,ruby] ---- # bad before(:each) do # ... end # bad before(:example) do # ... end # good before do # ... end ---- ==== `EnforcedStyle: each` [source,ruby] ---- # bad before(:example) do # ... end # bad before do # ... end # good before(:each) do # ... end ---- ==== `EnforcedStyle: example` [source,ruby] ---- # bad before(:each) do # ... end # bad before do # ... end # good before(:example) do # ... end ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `implicit` | `implicit`, `each`, `example` |=== === References * https://rspec.rubystyle.guide/#redundant-beforeeach * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument == RSpec/HooksBeforeExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.29 | - |=== Checks for before/around/after hooks that come after an example. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples == RSpec/IdenticalEqualityAssertion |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | No | 2.4 | - |=== Checks for equality assertions with identical expressions on both sides. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion == 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 [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 * https://rspec.rubystyle.guide/#implicit-block-expectations * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitBlockExpectation == RSpec/ImplicitExpect |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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 ==== `EnforcedStyle: is_expected` (default) [source,ruby] ---- # bad it { should be_truthy } # good it { is_expected.to be_truthy } ---- ==== `EnforcedStyle: should` [source,ruby] ---- # bad it { is_expected.to be_truthy } # good it { should be_truthy } ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `is_expected` | `is_expected`, `should` |=== === References * https://rspec.rubystyle.guide/#use-expect * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect == RSpec/ImplicitSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.29 | 2.13 |=== Checks for usage of implicit subject (`is_expected` / `should`). This cop can be configured using the `EnforcedStyle` option === Examples ==== `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` [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` [source,ruby] ---- # bad it { is_expected.to be_truthy } # good it { expect(subject).to be_truthy } ---- ==== `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 |=== | Name | Default value | Configurable values | EnforcedStyle | `single_line_only` | `single_line_only`, `single_statement_only`, `disallow`, `require_implicit` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject == RSpec/InstanceSpy |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.12 | - |=== Checks for `instance_double` used with `have_received`. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceSpy == 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 [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 [source,ruby] ---- # rubocop.yml # RSpec/InstanceVariable: # AssignmentOnly: false # 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 |=== | Name | Default value | Configurable values | AssignmentOnly | `false` | Boolean |=== === References * https://rspec.rubystyle.guide/#instance-variables * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable == RSpec/ItBehavesLike |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.13 | - |=== Checks that only one `it_behaves_like` style is used. === Examples ==== `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` [source,ruby] ---- # bad it_behaves_like 'a foo' # good it_should_behave_like 'a foo' ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `it_behaves_like` | `it_behaves_like`, `it_should_behave_like` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike == RSpec/IteratedExpectation |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.14 | - |=== Check that `all` matcher is used instead of iterating over an array. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IteratedExpectation == RSpec/LeadingSubject |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.7 | 1.14 |=== Enforce that subject is the first definition in the test. === 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 * https://rspec.rubystyle.guide/#leading-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject == 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 ==== 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 * https://rspec.rubystyle.guide/#declare-constants * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration == RSpec/LetBeforeExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.16 | 1.22 |=== Checks for `let` definitions that come after an example. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetBeforeExamples == 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 [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 ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetSetup == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageChain == 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 ==== `EnforcedStyle: allow` (default) [source,ruby] ---- # bad expect(foo).to receive(:bar) # good allow(foo).to receive(:bar) ---- ==== `EnforcedStyle: expect` [source,ruby] ---- # bad allow(foo).to receive(:bar) # good expect(foo).to receive(:bar) ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `allow` | `allow`, `expect` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageExpectation == 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 ==== `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` [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 |=== | Name | Default value | Configurable values | EnforcedStyle | `have_received` | `have_received`, `receive` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies == 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 [source,ruby] ---- # bad describe do end RSpec.describe do end # good describe TestedClass do end describe "A feature example" do end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes == 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 [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) [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` [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 ---- ==== configuration [source,ruby] ---- # .rubocop.yml # RSpec/MultipleExpectations: # Max: 2 # not flagged by rubocop describe UserCreator do it 'builds a user' do expect(user.name).to eq("John") expect(user.age).to eq(22) end end ---- === Configurable attributes |=== | Name | Default value | Configurable values | Max | `1` | Integer |=== === References * https://rspec.rubystyle.guide/#expectation-per-example * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations == 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 [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 [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 [source,ruby] ---- # rubocop.yml # RSpec/MultipleMemoizedHelpers: # Max: 1 # bad describe MyClass do let(:foo) { [] } let(:bar) { [] } end ---- === Configurable attributes |=== | Name | Default value | Configurable values | AllowSubject | `true` | Boolean | Max | `5` | Integer |=== === References * https://rspec.rubystyle.guide/#let-blocks * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers == RSpec/MultipleSubjects |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleSubjects == 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 ==== `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` [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 |=== | Name | Default value | Configurable values | EnforcedStyle | `always` | `always`, `named_only` | IgnoreSharedExamples | `true` | Boolean |=== === References * https://rspec.rubystyle.guide/#use-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject == 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 [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) [source,ruby] ---- # bad describe Foo do context 'foo' do context 'bar' do context 'baz' do # flagged by rubocop end end end end ---- ==== `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)` [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]` [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 |=== | Name | Default value | Configurable values | Max | `3` | Integer | AllowedGroups | `[]` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups == RSpec/NoExpectationExample |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | 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 [source,ruby] ---- # bad it do a? end # good it do expect(a?).to be(true) end ---- ==== `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 |=== | Name | Default value | Configurable values | AllowedPatterns | `^expect_`, `^assert_` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample == RSpec/NotToNot |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.4 | - |=== Checks for consistent method usage for negating expectations. === Examples ==== `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` [source,ruby] ---- # bad it '...' do expect(false).not_to be_true end # good it '...' do expect(false).to_not be_true end ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `not_to` | `not_to`, `to_not` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NotToNot == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending == RSpec/PendingWithoutReason |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | No | 2.16 | - |=== Checks for pending or skipped examples without reason. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PendingWithoutReason == RSpec/PredicateMatcher |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes (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 ==== 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 [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 [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) ---- ==== 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 |=== | Name | Default value | Configurable values | Strict | `true` | Boolean | EnforcedStyle | `inflected` | `inflected`, `explicit` | AllowedExplicitMatchers | `[]` | Array |=== === References * https://rspec.rubystyle.guide/#predicate-matchers * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PredicateMatcher == RSpec/ReceiveCounts |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.26 | - |=== Check for `once` and `twice` receive counts matchers usage. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts == RSpec/ReceiveNever |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.28 | - |=== Prefer `not_to receive(...)` over `receive(...).never`. === Examples [source,ruby] ---- # bad expect(foo).to receive(:bar).never # good expect(foo).not_to receive(:bar) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedDescription == 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 [source,ruby] ---- it 'is valid' do expect(user).to be_valid end it 'validates the user' do expect(user).to be_valid end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExample == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupBody == RSpec/RepeatedExampleGroupDescription |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.38 | - |=== Check for repeated example group descriptions. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupDescription == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample == RSpec/ReturnFromStub |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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 ==== `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` [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 |=== | Name | Default value | Configurable values | EnforcedStyle | `and_return` | `and_return`, `block` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReturnFromStub == RSpec/ScatteredLet |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.14 | 1.39 |=== Checks for let scattered across the example group. Group lets together === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredLet == RSpec/ScatteredSetup |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.10 | - |=== Checks for setup scattered across multiple hooks in an example group. Unify `before`, `after`, and `around` hooks when possible. === Examples [source,ruby] ---- # bad describe Foo do before { setup1 } before { setup2 } end # good describe Foo do before do setup1 setup2 end end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredSetup == RSpec/SharedContext |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext == RSpec/SharedExamples |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.25 | - |=== Enforces use of string to titleize shared examples. === Examples [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' ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples == RSpec/SingleArgumentMessageChain |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.9 | 1.10 |=== Checks that chains of messages contain more than one element. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain == RSpec/SortMetadata |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.14 | - |=== Sort RSpec metadata alphabetically. === 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' ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StubbedMock == RSpec/SubjectDeclaration |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | No | 2.5 | - |=== Ensure that subject is defined using subject helper. === 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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectDeclaration == 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 [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 * https://rspec.rubystyle.guide/#dont-stub-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectStub == 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 [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 * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UnspecifiedException == RSpec/VariableDefinition |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.40 | - |=== Checks that memoized helpers names are symbols or strings. === Examples ==== 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 [source,ruby] ---- # bad subject(:user) { create_user } let(:user_name) { 'Adam' } # good subject('user') { create_user } let('user_name') { 'Adam' } ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `symbols` | `symbols`, `strings` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableDefinition == 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 ==== 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 [source,ruby] ---- # bad subject(:user_name_1) { 'Adam' } let(:user_name_2) { 'Adam' } # good subject(:userName1) { 'Adam' } let(:userName2) { 'Adam' } ---- ==== 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 |=== | Name | Default value | Configurable values | EnforcedStyle | `snake_case` | `snake_case`, `camelCase` | AllowedPatterns | `[]` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName == RSpec/VerifiedDoubleReference |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes (Unsafe) | 2.10.0 | 2.12 |=== Checks for consistent verified double reference style. Only investigates references that are one of the supported styles. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. === Examples ==== `EnforcedStyle: constant` (default) [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 ---- ==== `EnforcedStyle: string` [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 not in the supported style list. No enforcement [source,ruby] ---- # good let(:foo) do instance_double(@klass, method_name: 'returned_value') end ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `constant` | `constant`, `string` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference == 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 [source,ruby] ---- # bad let(:foo) do double(method_name: 'returned value') end # bad let(:foo) do double("ClassName", method_name: 'returned value') end # good let(:foo) do instance_double("ClassName", method_name: 'returned value') end ---- === Configurable attributes |=== | Name | Default value | Configurable values | IgnoreNameless | `true` | Boolean | IgnoreSymbolicNames | `false` | Boolean |=== === References * https://rspec.rubystyle.guide/#doubles * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles == RSpec/VoidExpect |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.16 | - |=== Checks void `expect()`. === Examples [source,ruby] ---- # bad expect(something) # good expect(something).to be(1) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect == RSpec/Yield |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.32 | - |=== Checks for calling a block within a stub. === Examples [source,ruby] ---- # bad allow(foo).to receive(:bar) { |&block| block.call(1) } # good expect(foo).to receive(:bar).and_yield(1) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Yield rubocop-rspec-2.16.0/docs/modules/ROOT/pages/cops_rspec_capybara.adoc000066400000000000000000000147011434604127600255110ustar00rootroot00000000000000= RSpec/Capybara == RSpec/Capybara/CurrentPathExpectation |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.18 | 2.0 |=== Checks that no expectations are set on Capybara's `current_path`. The https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method[`have_current_path` matcher] should be used on `page` to set expectations on Capybara's current path, since it uses https://github.com/teamcapybara/capybara/blob/master/README.md#asynchronous-javascript-ajax-and-friends[Capybara's waiting functionality] which ensures that preceding actions (like `click_link`) have completed. This cop does not support autocorrection in some cases. === Examples [source,ruby] ---- # bad expect(current_path).to eq('/callback') # good expect(page).to have_current_path('/callback') # bad (does not support autocorrection) expect(page.current_path).to match(variable) # good expect(page).to have_current_path('/callback') ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/CurrentPathExpectation == RSpec/Capybara/FeatureMethods |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.17 | 2.0 |=== Checks for consistent method usage in feature specs. By default, the cop disables all Capybara-specific methods that have the same native RSpec method (e.g. are just aliases). Some teams however may prefer using some of the Capybara methods (like `feature`) to make it obvious that the test uses Capybara, while still disable the rest of the methods, like `given` (alias for `let`), `background` (alias for `before`), etc. You can configure which of the methods to be enabled by using the EnabledMethods configuration option. === Examples [source,ruby] ---- # bad feature 'User logs in' do given(:user) { User.new } background do visit new_session_path end scenario 'with OAuth' do # ... end end # good describe 'User logs in' do let(:user) { User.new } before do visit new_session_path end it 'with OAuth' do # ... end end ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnabledMethods | `[]` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods == RSpec/Capybara/NegationMatcher |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.14 | - |=== Enforces use of `have_no_*` or `not_to` for negated expectations. === Examples ==== EnforcedStyle: not_to (default) [source,ruby] ---- # bad expect(page).to have_no_selector expect(page).to have_no_css('a') # good expect(page).not_to have_selector expect(page).not_to have_css('a') ---- ==== EnforcedStyle: have_no [source,ruby] ---- # bad expect(page).not_to have_selector expect(page).not_to have_css('a') # good expect(page).to have_no_selector expect(page).to have_no_css('a') ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `not_to` | `have_no`, `not_to` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/NegationMatcher == RSpec/Capybara/SpecificActions |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | No | 2.14 | - |=== Checks for there is a more specific actions offered by Capybara. === Examples [source,ruby] ---- # bad find('a').click find('button.cls').click find('a', exact_text: 'foo').click find('div button').click # good click_link click_button(class: 'cls') click_link(exact_text: 'foo') find('div').click_button ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificActions == RSpec/Capybara/SpecificFinders |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.13 | - |=== Checks if there is a more specific finder offered by Capybara. === Examples [source,ruby] ---- # bad find('#some-id') find('[visible][id=some-id]') # good find_by_id('some-id') find_by_id('some-id', visible: true) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificFinders == RSpec/Capybara/SpecificMatcher |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | No | 2.12 | - |=== Checks for there is a more specific matcher offered by Capybara. === Examples [source,ruby] ---- # bad expect(page).to have_selector('button') expect(page).to have_no_selector('button.cls') expect(page).to have_css('button') expect(page).to have_no_css('a.cls', href: 'http://example.com') expect(page).to have_css('table.cls') expect(page).to have_css('select') expect(page).to have_css('input', exact_text: 'foo') # good expect(page).to have_button expect(page).to have_no_button(class: 'cls') expect(page).to have_button expect(page).to have_no_link('foo', class: 'cls', href: 'http://example.com') expect(page).to have_table(class: 'cls') expect(page).to have_select expect(page).to have_field('foo') ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificMatcher == RSpec/Capybara/VisibilityMatcher |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | No | 1.39 | 2.0 |=== Checks for boolean visibility in Capybara finders. Capybara lets you find elements that match a certain visibility using the `:visible` option. `:visible` accepts both boolean and symbols as values, however using booleans can have unwanted effects. `visible: false` does not find just invisible elements, but both visible and invisible elements. For expressiveness and clarity, use one of the symbol values, `:all`, `:hidden` or `:visible`. Read more in https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all[the documentation]. === Examples [source,ruby] ---- # bad expect(page).to have_selector('.foo', visible: false) expect(page).to have_css('.foo', visible: true) expect(page).to have_link('my link', visible: false) # good expect(page).to have_selector('.foo', visible: :visible) expect(page).to have_css('.foo', visible: :all) expect(page).to have_link('my link', visible: :hidden) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/VisibilityMatcher rubocop-rspec-2.16.0/docs/modules/ROOT/pages/cops_rspec_factorybot.adoc000066400000000000000000000132431434604127600261030ustar00rootroot00000000000000= RSpec/FactoryBot == RSpec/FactoryBot/AttributeDefinedStatically |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.28 | 2.0 |=== Always declare attribute values as blocks. === Examples [source,ruby] ---- # bad kind [:active, :rejected].sample # good kind { [:active, :rejected].sample } # bad closed_at 1.day.from_now # good closed_at { 1.day.from_now } # bad count 1 # good count { 1 } ---- === Configurable attributes |=== | Name | Default value | Configurable values | Include | `spec/factories.rb`, `+spec/factories/**/*.rb+`, `+features/support/factories/**/*.rb+` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/AttributeDefinedStatically == RSpec/FactoryBot/ConsistentParenthesesStyle |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.14 | - |=== Use a consistent style for parentheses in factory bot calls. === Examples [source,ruby] ---- # bad create :user build(:user) create(:login) create :login ---- ==== `EnforcedStyle: require_parentheses` (default) [source,ruby] ---- # good create(:user) create(:user) create(:login) build(:login) ---- ==== `EnforcedStyle: omit_parentheses` [source,ruby] ---- # good create :user build :user create :login create :login # also good # when method name and first argument are not on same line create( :user ) build( :user, name: 'foo' ) ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `require_parentheses` | `require_parentheses`, `omit_parentheses` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/ConsistentParenthesesStyle == RSpec/FactoryBot/CreateList |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.25 | 2.0 |=== Checks for create_list usage. This cop can be configured using the `EnforcedStyle` option === Examples ==== `EnforcedStyle: create_list` (default) [source,ruby] ---- # bad 3.times { create :user } # good create_list :user, 3 # bad 3.times { create :user, age: 18 } # good - index is used to alter the created models attributes 3.times { |n| create :user, age: n } # good - contains a method call, may return different values 3.times { create :user, age: rand } ---- ==== `EnforcedStyle: n_times` [source,ruby] ---- # bad create_list :user, 3 # good 3.times { create :user } ---- === Configurable attributes |=== | Name | Default value | Configurable values | Include | `+**/*_spec.rb+`, `+**/spec/**/*+`, `spec/factories.rb`, `+spec/factories/**/*.rb+`, `+features/support/factories/**/*.rb+` | Array | EnforcedStyle | `create_list` | `create_list`, `n_times` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/CreateList == RSpec/FactoryBot/FactoryClassName |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.37 | 2.0 |=== Use string value when setting the class attribute explicitly. This cop would promote faster tests by lazy-loading of application files. Also, this could help you suppress potential bugs in combination with external libraries by avoiding a preload of application files from the factory files. === Examples [source,ruby] ---- # bad factory :foo, class: Foo do end # good factory :foo, class: 'Foo' do end ---- === Configurable attributes |=== | Name | Default value | Configurable values | Include | `spec/factories.rb`, `+spec/factories/**/*.rb+`, `+features/support/factories/**/*.rb+` | Array |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/FactoryClassName == RSpec/FactoryBot/FactoryNameStyle |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.16 | - |=== Checks for name style for argument of FactoryBot::Syntax::Methods. === Examples ==== EnforcedStyle: symbol (default) [source,ruby] ---- # bad create('user') build "user", username: "NAME" # good create(:user) build :user, username: "NAME" ---- ==== EnforcedStyle: string [source,ruby] ---- # bad create(:user) build :user, username: "NAME" # good create('user') build "user", username: "NAME" ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `symbol` | `symbol`, `string` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/FactoryNameStyle == RSpec/FactoryBot/SyntaxMethods |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes (Unsafe) | 2.7 | - |=== Use shorthands from `FactoryBot::Syntax::Methods` in your specs. === Safety The autocorrection is marked as unsafe because the cop cannot verify whether you already include `FactoryBot::Syntax::Methods` in your test suite. If you're using Rails, add the following configuration to `spec/support/factory_bot.rb` and be sure to require that file in `rails_helper.rb`: [source,ruby] ---- RSpec.configure do |config| config.include FactoryBot::Syntax::Methods end ---- If you're not using Rails: [source,ruby] ---- RSpec.configure do |config| config.include FactoryBot::Syntax::Methods config.before(:suite) do FactoryBot.find_definitions end end ---- === Examples [source,ruby] ---- # bad FactoryBot.create(:bar) FactoryBot.build(:bar) FactoryBot.attributes_for(:bar) # good create(:bar) build(:bar) attributes_for(:bar) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/SyntaxMethods rubocop-rspec-2.16.0/docs/modules/ROOT/pages/cops_rspec_rails.adoc000066400000000000000000000074231434604127600250440ustar00rootroot00000000000000= RSpec/Rails == RSpec/Rails/AvoidSetupHook |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes | 2.4 | - |=== Checks that tests use RSpec `before` hook over Rails `setup` method. === Examples [source,ruby] ---- # bad setup do allow(foo).to receive(:bar) end # good before do allow(foo).to receive(:bar) end ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/AvoidSetupHook == RSpec/Rails/HaveHttpStatus |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | Yes | Yes (Unsafe) | 2.12 | - |=== Checks that tests use `have_http_status` instead of equality matchers. === Examples [source,ruby] ---- # bad expect(response.status).to be(200) # good expect(response).to have_http_status(200) ---- === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus == RSpec/Rails/HttpStatus |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Enabled | Yes | Yes | 1.23 | 2.0 |=== Enforces use of symbolic or numeric value to describe HTTP status. === Examples ==== `EnforcedStyle: symbolic` (default) [source,ruby] ---- # bad it { is_expected.to have_http_status 200 } it { is_expected.to have_http_status 404 } # good it { is_expected.to have_http_status :ok } it { is_expected.to have_http_status :not_found } it { is_expected.to have_http_status :success } it { is_expected.to have_http_status :error } ---- ==== `EnforcedStyle: numeric` [source,ruby] ---- # bad it { is_expected.to have_http_status :ok } it { is_expected.to have_http_status :not_found } # good it { is_expected.to have_http_status 200 } it { is_expected.to have_http_status 404 } it { is_expected.to have_http_status :success } it { is_expected.to have_http_status :error } ---- === Configurable attributes |=== | Name | Default value | Configurable values | EnforcedStyle | `symbolic` | `numeric`, `symbolic` |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HttpStatus == RSpec/Rails/InferredSpecType |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed | Pending | No | Yes (Unsafe) | 2.14 | - |=== Identifies redundant spec type. After setting up rspec-rails, you will have enabled `config.infer_spec_type_from_file_location!` by default in spec/rails_helper.rb. This cop works in conjunction with this config. If you disable this config, disable this cop as well. === Safety This cop is marked as unsafe because `config.infer_spec_type_from_file_location!` may not be enabled. === Examples [source,ruby] ---- # bad # spec/models/user_spec.rb RSpec.describe User, type: :model do end # good # spec/models/user_spec.rb RSpec.describe User do end # good # spec/models/user_spec.rb RSpec.describe User, type: :common do end ---- ==== `Inferences` configuration [source,ruby] ---- # .rubocop.yml # RSpec/Rails/InferredSpecType: # Inferences: # services: service # bad # spec/services/user_spec.rb RSpec.describe User, type: :service do end # good # spec/services/user_spec.rb RSpec.describe User do end # good # spec/services/user_spec.rb RSpec.describe User, type: :common do end ---- === Configurable attributes |=== | Name | Default value | Configurable values | Inferences | `{"channels"=>"channel", "controllers"=>"controller", "features"=>"feature", "generator"=>"generator", "helpers"=>"helper", "jobs"=>"job", "mailboxes"=>"mailbox", "mailers"=>"mailer", "models"=>"model", "requests"=>"request", "integration"=>"request", "api"=>"request", "routing"=>"routing", "system"=>"system", "views"=>"view"}` | |=== === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/InferredSpecType rubocop-rspec-2.16.0/docs/modules/ROOT/pages/development.adoc000066400000000000000000000026121434604127600240270ustar00rootroot00000000000000= 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]. == 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-rspec-2.16.0/docs/modules/ROOT/pages/index.adoc000066400000000000000000000036021434604127600226140ustar00rootroot00000000000000= RuboCop RSpec 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 https://relishapp.com/rspec/rspec-expectations/docs/syntax-configuration#disable-should-syntax[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://relishapp.com/rspec/rspec-core/v/3-7/docs/configuration/zero-monkey-patching-mode#monkey-patched-methods-are-undefined-with-%60disable-monkey-patching!%60[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-rspec-2.16.0/docs/modules/ROOT/pages/installation.adoc000066400000000000000000000003071434604127600242050ustar00rootroot00000000000000= 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-rspec-2.16.0/docs/modules/ROOT/pages/third_party_rspec_syntax_extensions.adoc000066400000000000000000000040731434604127600311220ustar00rootroot00000000000000= 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-rspec-2.16.0/docs/modules/ROOT/pages/upgrade_to_version_2.adoc000066400000000000000000000174171434604127600256350ustar00rootroot00000000000000= 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_pattern('#SharedGroups.context') ---- [source,ruby] ---- # Before def_node_search :examples?, (Includes::EXAMPLES + Examples::ALL).send_pattern # After def_node_search :examples?, send_pattern('{#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_pattern('#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-rspec-2.16.0/docs/modules/ROOT/pages/usage.adoc000066400000000000000000000056031434604127600226140ustar00rootroot00000000000000= 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`: ---- require: rubocop-rspec ---- or, if you are using several extensions: ---- require: - rubocop-rspec - rubocop-performance ---- Now you can run `rubocop` and it will automatically load the RuboCop RSpec cops together with the standard cops. === 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 --require rubocop-rspec ---- == Rake task [source,ruby] ---- RuboCop::RakeTask.new do |task| task.requires << '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-rspec-2.16.0/lib/000077500000000000000000000000001434604127600151405ustar00rootroot00000000000000rubocop-rspec-2.16.0/lib/rubocop-rspec.rb000066400000000000000000000042751434604127600202600ustar00rootroot00000000000000# frozen_string_literal: true require 'pathname' require 'yaml' require 'rubocop' require_relative 'rubocop/rspec' require_relative 'rubocop/rspec/inject' require_relative 'rubocop/rspec/language/node_pattern' require_relative 'rubocop/rspec/node' require_relative 'rubocop/rspec/version' require_relative 'rubocop/rspec/wording' # Dependent on `RuboCop::RSpec::Language::NodePattern`. require_relative 'rubocop/rspec/language' require_relative 'rubocop/rspec/factory_bot/language' require_relative 'rubocop/cop/rspec/mixin/capybara_help' require_relative 'rubocop/cop/rspec/mixin/css_selector' require_relative 'rubocop/cop/rspec/mixin/final_end_location' require_relative 'rubocop/cop/rspec/mixin/inside_example_group' 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/factory_bot' require_relative 'rubocop/rspec/hook' RuboCop::RSpec::Inject.defaults! 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::Cop::Style::TrailingCommaInArguments.singleton_class.prepend( Module.new do def autocorrect_incompatible_with super.push(RuboCop::Cop::RSpec::Capybara::CurrentPathExpectation) end end ) RuboCop::AST::Node.include(RuboCop::RSpec::Node) rubocop-rspec-2.16.0/lib/rubocop/000077500000000000000000000000001434604127600166115ustar00rootroot00000000000000rubocop-rspec-2.16.0/lib/rubocop/cop/000077500000000000000000000000001434604127600173725ustar00rootroot00000000000000rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/000077500000000000000000000000001434604127600205065ustar00rootroot00000000000000rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/align_left_let_brace.rb000066400000000000000000000021461434604127600251420ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/align_right_let_brace.rb000066400000000000000000000021671434604127600253300ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/any_instance.rb000066400000000000000000000020121434604127600235010ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/around_block.rb000066400000000000000000000045031434604127600234770ustar00rootroot00000000000000# 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) name, = *proxy find_arg_usage(block) do |usage| return if usage.include?(s(:lvar, name)) end add_offense( proxy, message: format(MSG_UNUSED_ARG, arg: 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-rspec-2.16.0/lib/rubocop/cop/rspec/base.rb000066400000000000000000000014271434604127600217510ustar00rootroot00000000000000# 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 extend RuboCop::RSpec::Language::NodePattern 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-rspec-2.16.0/lib/rubocop/cop/rspec/be.rb000066400000000000000000000020121434604127600214140ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/be_eq.rb000066400000000000000000000024271434604127600221130ustar00rootroot00000000000000# 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 {true false 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-rspec-2.16.0/lib/rubocop/cop/rspec/be_eql.rb000066400000000000000000000037041434604127600222660ustar00rootroot00000000000000# 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 {true false 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-rspec-2.16.0/lib/rubocop/cop/rspec/be_nil.rb000066400000000000000000000036071434604127600222710ustar00rootroot00000000000000# 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) 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.loc.expression, '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.loc.expression, 'be_nil') end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/before_after_all.rb000066400000000000000000000026331434604127600243120ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Check that before/after(:all) isn't being used. # # @example # # bad # # # # Faster but risk of state leaking between examples # # # describe MyClass do # before(:all) { Widget.create } # after(:all) { 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 = %i[before after].freeze # @!method before_or_after_all(node) def_node_matcher :before_or_after_all, <<-PATTERN $(send _ {:before :after} (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-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/000077500000000000000000000000001434604127600222705ustar00rootroot00000000000000rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb000066400000000000000000000112411434604127600277150ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Checks that no expectations are set on Capybara's `current_path`. # # The # https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method[`have_current_path` matcher] # should be used on `page` to set expectations on Capybara's # current path, since it uses # https://github.com/teamcapybara/capybara/blob/master/README.md#asynchronous-javascript-ajax-and-friends[Capybara's waiting functionality] # which ensures that preceding actions (like `click_link`) have # completed. # # This cop does not support autocorrection in some cases. # # @example # # bad # expect(current_path).to eq('/callback') # # # good # expect(page).to have_current_path('/callback') # # # bad (does not support autocorrection) # expect(page.current_path).to match(variable) # # # good # expect(page).to have_current_path('/callback') # class CurrentPathExpectation < ::RuboCop::Cop::Base extend AutoCorrector MSG = 'Do not set an RSpec expectation on `current_path` in ' \ 'Capybara feature specs - instead, use the ' \ '`have_current_path` matcher on `page`' RESTRICT_ON_SEND = %i[expect].freeze # @!method expectation_set_on_current_path(node) def_node_matcher :expectation_set_on_current_path, <<-PATTERN (send nil? :expect (send {(send nil? :page) nil?} :current_path)) PATTERN # Supported matchers: eq(...) / match(/regexp/) / match('regexp') # @!method as_is_matcher(node) def_node_matcher :as_is_matcher, <<-PATTERN (send #expectation_set_on_current_path ${:to :to_not :not_to} ${(send nil? :eq ...) (send nil? :match (regexp ...))}) PATTERN # @!method regexp_str_matcher(node) def_node_matcher :regexp_str_matcher, <<-PATTERN (send #expectation_set_on_current_path ${:to :to_not :not_to} $(send nil? :match (str $_))) PATTERN def self.autocorrect_incompatible_with [Style::TrailingCommaInArguments] end def on_send(node) expectation_set_on_current_path(node) do add_offense(node.loc.selector) do |corrector| next unless node.chained? autocorrect(corrector, node) end end end private def autocorrect(corrector, node) as_is_matcher(node.parent) do |to_sym, matcher_node| rewrite_expectation(corrector, node, to_sym, matcher_node) end regexp_str_matcher(node.parent) do |to_sym, matcher_node, regexp| rewrite_expectation(corrector, node, to_sym, matcher_node) convert_regexp_str_to_literal(corrector, matcher_node, regexp) end end def rewrite_expectation(corrector, node, to_symbol, matcher_node) current_path_node = node.first_argument corrector.replace(current_path_node, 'page') corrector.replace(node.parent.loc.selector, 'to') matcher_method = if to_symbol == :to 'have_current_path' else 'have_no_current_path' end corrector.replace(matcher_node.loc.selector, matcher_method) add_ignore_query_options(corrector, node) end def convert_regexp_str_to_literal(corrector, matcher_node, regexp_str) str_node = matcher_node.first_argument regexp_expr = Regexp.new(regexp_str).inspect corrector.replace(str_node, regexp_expr) end # `have_current_path` with no options will include the querystring # while `page.current_path` does not. # This ensures the option `ignore_query: true` is added # except when the expectation is a regexp or string def add_ignore_query_options(corrector, node) expectation_node = node.parent.last_argument expectation_last_child = expectation_node.children.last return if %i[regexp str].include?(expectation_last_child.type) corrector.insert_after( expectation_last_child, ', ignore_query: true' ) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/feature_methods.rb000066400000000000000000000060461434604127600260010ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Checks for consistent method usage in feature specs. # # By default, the cop disables all Capybara-specific methods that have # the same native RSpec method (e.g. are just aliases). Some teams # however may prefer using some of the Capybara methods (like `feature`) # to make it obvious that the test uses Capybara, while still disable # the rest of the methods, like `given` (alias for `let`), `background` # (alias for `before`), etc. You can configure which of the methods to # be enabled by using the EnabledMethods configuration option. # # @example # # bad # feature 'User logs in' do # given(:user) { User.new } # # background do # visit new_session_path # end # # scenario 'with OAuth' do # # ... # end # end # # # good # describe 'User logs in' do # let(:user) { User.new } # # before do # visit new_session_path # end # # it 'with OAuth' do # # ... # end # end # class FeatureMethods < Base extend AutoCorrector include InsideExampleGroup MSG = 'Use `%s` instead of `%s`.' # https://github.com/teamcapybara/capybara/blob/e283c1aeaa72441f5403963577e16333bf111a81/lib/capybara/rspec/features.rb#L31-L36 MAP = { background: :before, scenario: :it, xscenario: :xit, given: :let, given!: :let!, feature: :describe }.freeze # @!method capybara_speak(node) def_node_matcher :capybara_speak, <<-PATTERN {#{MAP.keys.map(&:inspect).join(' ')}} PATTERN # @!method feature_method(node) def_node_matcher :feature_method, <<-PATTERN (block $(send #rspec? $#capybara_speak ...) ...) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless inside_example_group?(node) feature_method(node) do |send_node, match| next if enabled?(match) add_offense(send_node.loc.selector) do |corrector| corrector.replace(send_node.loc.selector, MAP[match].to_s) end end end def message(range) name = range.source.to_sym format(MSG, method: name, replacement: MAP[name]) end private def enabled?(method_name) enabled_methods.include?(method_name) end def enabled_methods cop_config .fetch('EnabledMethods', []) .map(&:to_sym) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/negation_matcher.rb000066400000000000000000000061721434604127600261320ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Enforces use of `have_no_*` or `not_to` for negated expectations. # # @example EnforcedStyle: not_to (default) # # bad # expect(page).to have_no_selector # expect(page).to have_no_css('a') # # # good # expect(page).not_to have_selector # expect(page).not_to have_css('a') # # @example EnforcedStyle: have_no # # bad # expect(page).not_to have_selector # expect(page).not_to have_css('a') # # # good # expect(page).to have_no_selector # expect(page).to have_no_css('a') # class NegationMatcher < ::RuboCop::Cop::Base extend AutoCorrector include ConfigurableEnforcedStyle MSG = 'Use `expect(...).%s %s`.' CAPYBARA_MATCHERS = %w[ selector css xpath text title current_path link button field checked_field unchecked_field select table sibling ancestor ].freeze POSITIVE_MATCHERS = Set.new(CAPYBARA_MATCHERS) { |element| :"have_#{element}" }.freeze NEGATIVE_MATCHERS = Set.new(CAPYBARA_MATCHERS) { |element| :"have_no_#{element}" } .freeze RESTRICT_ON_SEND = (POSITIVE_MATCHERS + NEGATIVE_MATCHERS).freeze # @!method not_to?(node) def_node_matcher :not_to?, <<~PATTERN (send ... :not_to (send nil? %POSITIVE_MATCHERS ...)) PATTERN # @!method have_no?(node) def_node_matcher :have_no?, <<~PATTERN (send ... :to (send nil? %NEGATIVE_MATCHERS ...)) PATTERN def on_send(node) return unless offense?(node.parent) matcher = node.method_name.to_s add_offense(offense_range(node), message: message(matcher)) do |corrector| corrector.replace(node.parent.loc.selector, replaced_runner) corrector.replace(node.loc.selector, replaced_matcher(matcher)) end end private def offense?(node) (style == :have_no && not_to?(node)) || (style == :not_to && have_no?(node)) end def offense_range(node) node.parent.loc.selector.with(end_pos: node.loc.selector.end_pos) end def message(matcher) format(MSG, runner: replaced_runner, matcher: replaced_matcher(matcher)) end def replaced_runner case style when :have_no 'to' when :not_to 'not_to' end end def replaced_matcher(matcher) case style when :have_no matcher.sub('have_', 'have_no_') when :not_to matcher.sub('have_no_', 'have_') end end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/specific_actions.rb000066400000000000000000000050521434604127600261240ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Checks for there is a more specific actions offered by Capybara. # # @example # # # bad # find('a').click # find('button.cls').click # find('a', exact_text: 'foo').click # find('div button').click # # # good # click_link # click_button(class: 'cls') # click_link(exact_text: 'foo') # find('div').click_button # class SpecificActions < ::RuboCop::Cop::Base MSG = "Prefer `%s` over `find('%s').click`." RESTRICT_ON_SEND = %i[click].freeze SPECIFIC_ACTION = { 'button' => 'button', 'a' => 'link' }.freeze # @!method click_on_selector(node) def_node_matcher :click_on_selector, <<-PATTERN (send _ :find (str $_) ...) PATTERN def on_send(node) click_on_selector(node.receiver) do |arg| next unless supported_selector?(arg) # Always check the last selector in the case of multiple selectors # separated by whitespace. # because the `.click` is executed on the element to # which the last selector points. next unless (selector = last_selector(arg)) next unless (action = specific_action(selector)) next unless CapybaraHelp.specific_option?(node.receiver, arg, action) next unless CapybaraHelp.specific_pseudo_classes?(arg) range = offense_range(node, node.receiver) add_offense(range, message: message(action, selector)) end end private def specific_action(selector) SPECIFIC_ACTION[last_selector(selector)] end def supported_selector?(selector) !selector.match?(/[>,+~]/) end def last_selector(arg) arg.split.last[/^\w+/, 0] end def offense_range(node, receiver) receiver.loc.selector.with(end_pos: node.loc.expression.end_pos) end def message(action, selector) format(MSG, good_action: good_action(action), selector: selector) end def good_action(action) "click_#{action}" end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/specific_finders.rb000066400000000000000000000047271434604127600261260ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Checks if there is a more specific finder offered by Capybara. # # @example # # bad # find('#some-id') # find('[visible][id=some-id]') # # # good # find_by_id('some-id') # find_by_id('some-id', visible: true) # class SpecificFinders < ::RuboCop::Cop::Base extend AutoCorrector include RangeHelp MSG = 'Prefer `find_by` over `find`.' RESTRICT_ON_SEND = %i[find].freeze # @!method find_argument(node) def_node_matcher :find_argument, <<~PATTERN (send _ :find (str $_) ...) PATTERN def on_send(node) find_argument(node) do |arg| next if CssSelector.multiple_selectors?(arg) on_attr(node, arg) if attribute?(arg) on_id(node, arg) if CssSelector.id?(arg) end end private def on_attr(node, arg) return unless (id = CssSelector.attributes(arg)['id']) register_offense(node, replaced_arguments(arg, id)) end def on_id(node, arg) register_offense(node, "'#{arg.to_s.delete('#')}'") end def attribute?(arg) CssSelector.attribute?(arg) && CssSelector.common_attributes?(arg) end def register_offense(node, arg_replacement) add_offense(offense_range(node)) do |corrector| corrector.replace(node.loc.selector, 'find_by_id') corrector.replace(node.first_argument.loc.expression, arg_replacement) end end def replaced_arguments(arg, id) options = to_options(CssSelector.attributes(arg)) options.empty? ? id : "#{id}, #{options}" end def to_options(attrs) attrs.each.map do |key, value| next if key == 'id' "#{key}: #{value}" end.compact.join(', ') end def offense_range(node) range_between(node.loc.selector.begin_pos, end_pos(node)) end def end_pos(node) if node.loc.end node.loc.end.end_pos else node.loc.expression.end_pos end end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/specific_matcher.rb000066400000000000000000000050631434604127600261110ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Checks for there is a more specific matcher offered by Capybara. # # @example # # # bad # expect(page).to have_selector('button') # expect(page).to have_no_selector('button.cls') # expect(page).to have_css('button') # expect(page).to have_no_css('a.cls', href: 'http://example.com') # expect(page).to have_css('table.cls') # expect(page).to have_css('select') # expect(page).to have_css('input', exact_text: 'foo') # # # good # expect(page).to have_button # expect(page).to have_no_button(class: 'cls') # expect(page).to have_button # expect(page).to have_no_link('foo', class: 'cls', href: 'http://example.com') # expect(page).to have_table(class: 'cls') # expect(page).to have_select # expect(page).to have_field('foo') # class SpecificMatcher < ::RuboCop::Cop::Base MSG = 'Prefer `%s` over `%s`.' RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css have_no_css].freeze SPECIFIC_MATCHER = { 'button' => 'button', 'a' => 'link', 'table' => 'table', 'select' => 'select', 'input' => 'field' }.freeze # @!method first_argument(node) def_node_matcher :first_argument, <<-PATTERN (send nil? _ (str $_) ... ) PATTERN def on_send(node) first_argument(node) do |arg| next unless (matcher = specific_matcher(arg)) next if CssSelector.multiple_selectors?(arg) next unless CapybaraHelp.specific_option?(node, arg, matcher) next unless CapybaraHelp.specific_pseudo_classes?(arg) add_offense(node, message: message(node, matcher)) end end private def specific_matcher(arg) splitted_arg = arg[/^\w+/, 0] SPECIFIC_MATCHER[splitted_arg] end def message(node, matcher) format(MSG, good_matcher: good_matcher(node, matcher), bad_matcher: node.method_name) end def good_matcher(node, matcher) node.method_name .to_s .gsub(/selector|css/, matcher.to_s) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb000066400000000000000000000050371434604127600265140ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module Capybara # Checks for boolean visibility in Capybara finders. # # Capybara lets you find elements that match a certain visibility using # the `:visible` option. `:visible` accepts both boolean and symbols as # values, however using booleans can have unwanted effects. `visible: # false` does not find just invisible elements, but both visible and # invisible elements. For expressiveness and clarity, use one of the # symbol values, `:all`, `:hidden` or `:visible`. # Read more in # https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all[the documentation]. # # @example # # bad # expect(page).to have_selector('.foo', visible: false) # expect(page).to have_css('.foo', visible: true) # expect(page).to have_link('my link', visible: false) # # # good # expect(page).to have_selector('.foo', visible: :visible) # expect(page).to have_css('.foo', visible: :all) # expect(page).to have_link('my link', visible: :hidden) # class VisibilityMatcher < ::RuboCop::Cop::Base MSG_FALSE = 'Use `:all` or `:hidden` instead of `false`.' MSG_TRUE = 'Use `:visible` instead of `true`.' CAPYBARA_MATCHER_METHODS = %w[ button checked_field css field link select selector table unchecked_field xpath ].flat_map do |element| ["have_#{element}".to_sym, "have_no_#{element}".to_sym] end RESTRICT_ON_SEND = CAPYBARA_MATCHER_METHODS # @!method visible_true?(node) def_node_matcher :visible_true?, <<~PATTERN (send nil? #capybara_matcher? ... (hash <$(pair (sym :visible) true) ...>)) PATTERN # @!method visible_false?(node) def_node_matcher :visible_false?, <<~PATTERN (send nil? #capybara_matcher? ... (hash <$(pair (sym :visible) false) ...>)) PATTERN def on_send(node) visible_false?(node) { |arg| add_offense(arg, message: MSG_FALSE) } visible_true?(node) { |arg| add_offense(arg, message: MSG_TRUE) } end private def capybara_matcher?(method_name) CAPYBARA_MATCHER_METHODS.include? method_name end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/change_by_zero.rb000066400000000000000000000110761434604127600240160ustar00rootroot00000000000000# 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 MSG = 'Prefer `not_to change` over `to change.by(0)`.' MSG_COMPOUND = 'Prefer %s with compound expectations ' \ 'over `change.by(0)`.' RESTRICT_ON_SEND = %i[change].freeze # @!method expect_change_with_arguments(node) def_node_matcher :expect_change_with_arguments, <<-PATTERN (send (send nil? :change ...) :by (int 0)) PATTERN # @!method expect_change_with_block(node) def_node_matcher :expect_change_with_block, <<-PATTERN (send (block (send nil? :change) (args) (send (...) $_)) :by (int 0)) PATTERN # @!method change_nodes(node) def_node_search :change_nodes, <<-PATTERN $(send nil? :change ...) PATTERN def on_send(node) expect_change_with_arguments(node.parent) do check_offense(node.parent) end expect_change_with_block(node.parent.parent) do check_offense(node.parent.parent) end end private def check_offense(node) expression = node.loc.expression if compound_expectations?(node) add_offense(expression, message: message_compound) do |corrector| autocorrect_compound(corrector, node) end else add_offense(expression) do |corrector| autocorrect(corrector, node) end end end def compound_expectations?(node) %i[and or & |].include?(node.parent.method_name) end def autocorrect(corrector, node) corrector.replace(node.parent.loc.selector, 'not_to') range = node.loc.dot.with(end_pos: node.loc.expression.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) range = node.loc.dot.with(end_pos: node.loc.expression.end_pos) corrector.remove(range) end end def negated_matcher cop_config['NegatedMatcher'] end def message_compound format(MSG_COMPOUND, preferred: preferred_method) end def preferred_method negated_matcher ? "`#{negated_matcher}`" : 'negated matchers' end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/class_check.rb000066400000000000000000000045321434604127600233010ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/context_method.rb000066400000000000000000000022671434604127600240660ustar00rootroot00000000000000# 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?) ...) ...) 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-rspec-2.16.0/lib/rubocop/cop/rspec/context_wording.rb000066400000000000000000000057741434604127600242650ustar00rootroot00000000000000# 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 https://rspec.rubystyle.guide/#context-descriptions # @see http://www.betterspecs.org/#contexts # # @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 = 'Context description should match %s.' # @!method context_wording(node) def_node_matcher :context_wording, <<-PATTERN (block (send #rspec? { :context :shared_context } $(str $_) ...) ...) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_wording(node) do |context, description| if bad_pattern?(description) message = format(MSG, patterns: expect_patterns) 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 bad_pattern?(description) return false if allowed_patterns.empty? !matches_allowed_pattern?(description) 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', [])) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/describe_class.rb000066400000000000000000000045101434604127600240000ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/describe_method.rb000066400000000000000000000021211434604127600241470ustar00rootroot00000000000000# 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_argument(node) def_node_matcher :second_argument, <<~PATTERN (block (send #rspec? :describe _first_argument $(str _) ...) ... ) PATTERN def on_top_level_group(node) second_argument = second_argument(node) return unless second_argument return if second_argument.str_content.start_with?('#', '.') add_offense(second_argument) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/describe_symbol.rb000066400000000000000000000014561434604127600242060ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/described_class.rb000066400000000000000000000153511434604127600241510ustar00rootroot00000000000000# 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` and `SkipBlocks` # options. # # @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 `EnforcedStyle: explicit` # # bad # describe MyClass do # subject { described_class.do_something } # end # # # good # describe MyClass do # subject { MyClass.do_something } # end # # 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. # # @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 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 ...) ...) PATTERN # @!method rspec_block?(node) def_node_matcher :rspec_block?, block_pattern('#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) || node.const_type? node.each_child_node do |child| find_usage(child, &block) end 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) node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks'] 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 unless node.const_type? # E.g. `described_class::CONSTANT` return if contains_described_class?(node) nearest_described_class, = node.each_ancestor(:block) .map { |ancestor| described_constant(ancestor) }.find(&:itself) return 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, name = *node # rubocop:disable InternalAffairs/NodeDestructuring 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-rspec-2.16.0/lib/rubocop/cop/rspec/described_class_module_wrapping.rb000066400000000000000000000015351434604127600274240ustar00rootroot00000000000000# 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 find_rspec_blocks(node) def_node_search :find_rspec_blocks, block_pattern('#ExampleGroups.all') def on_module(node) find_rspec_blocks(node) do add_offense(node) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/dialect.rb000066400000000000000000000037571434604127600224540ustar00rootroot00000000000000# 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 # # By default all of the RSpec methods and aliases are allowed. By setting # a config like: # # RSpec/Dialect: # PreferredMethods: # context: 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_pattern('#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-rspec-2.16.0/lib/rubocop/cop/rspec/duplicated_metadata.rb000066400000000000000000000023141434604127600250110ustar00rootroot00000000000000# 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, _pairs) 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.location.expression, side: :left ), :left ) ) end def duplicated?(node) node.left_siblings.any? do |sibling| sibling.eql?(node) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/empty_example_group.rb000066400000000000000000000133241434604127600251230ustar00rootroot00000000000000# 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_pattern('#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_pattern( '{#Examples.all #ExampleGroups.all #Includes.all}' )} #{send_pattern('{#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_pattern('#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? (begin <#examples_directly_or_in_block? ...>) } PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return if node.each_ancestor(:def, :defs).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.if_type? || body.case_type? !examples_in_branches?(body) else !examples?(body) end end def conditionals_with_examples?(body) return unless body.begin_type? || body.case_type? body.each_descendant(:if, :case).any? do |condition_node| examples_in_branches?(condition_node) end end def examples_in_branches?(condition_node) condition_node.branches.any? { |branch| examples?(branch) } end def removed_range(node) range_by_whole_lines( node.location.expression, include_final_newline: true ) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/empty_hook.rb000066400000000000000000000022101434604127600232040ustar00rootroot00000000000000# 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_pattern('#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.loc.expression, side: :left) ) end end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/empty_line_after_example.rb000066400000000000000000000037341434604127600261030ustar00rootroot00000000000000# 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 unless next_sibling return unless example?(next_sibling) next_sibling.single_line? end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/empty_line_after_example_group.rb000066400000000000000000000017051434604127600273130ustar00rootroot00000000000000# 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 example_group?(node) missing_separating_line_offense(node) do |method| format(MSG, example_group: method) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/empty_line_after_final_let.rb000066400000000000000000000017411434604127600264010ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/empty_line_after_hook.rb000066400000000000000000000040011434604127600253740ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/empty_line_after_subject.rb000066400000000000000000000015661434604127600261100ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/example_length.rb000066400000000000000000000031541434604127600240320ustar00rootroot00000000000000# 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 literals you want to fold with `CountAsOne`. # Available are: 'array', 'hash', and 'heredoc'. Each literal # will be counted as one line regardless of its actual size. # # @example CountAsOne: ['array', 'heredoc'] # # it do # array = [ # +1 # 1, # 2 # ] # # hash = { # +3 # key: 'value' # } # # msg = <<~HEREDOC # +1 # Heredoc # content. # HEREDOC # end # 5 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-rspec-2.16.0/lib/rubocop/cop/rspec/example_without_description.rb000066400000000000000000000051101434604127600266510ustar00rootroot00000000000000# 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. # # 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 `EnforcedStyle: always_allow` (default) # # 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 } # it 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) 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-rspec-2.16.0/lib/rubocop/cop/rspec/example_wording.rb000066400000000000000000000103331434604127600242170ustar00rootroot00000000000000# 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 # # The autocorrect is experimental - use with care! It can be configured # with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only). # # 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 # # # 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_IT = "Do not repeat 'it' when describing your tests." MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \ 'insufficient.' SHOULD_PREFIX = /\Ashould(?:n'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?(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.loc.expression 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) 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 when :begin 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-rspec-2.16.0/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb000066400000000000000000000047721434604127600266230ustar00rootroot00000000000000# 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 _ {#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) return true if text.start_with?(' ') || text.end_with?(' ') text.match?(/[^\n ] +[^ ]/) end # @param text [String] def strip_excessive_whitespace(text) text.strip.gsub(/ +/, ' ') 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.loc.expression 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 when :begin node.source end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/expect_actual.rb000066400000000000000000000050121434604127600236520ustar00rootroot00000000000000# 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 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 SUPPORTED_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, matcher, expected| add_offense(actual.source_range) do |corrector| next unless SUPPORTED_MATCHERS.include?(matcher) next if literal?(expected) swap(corrector, actual, expected) end end end private # This is not implement 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?(&method(:literal?)) end def swap(corrector, actual, expected) corrector.replace(actual.source_range, expected.source) corrector.replace(expected.source_range, actual.source) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/expect_change.rb000066400000000000000000000054001434604127600236270ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks for consistent style of change matcher. # # Enforces either passing object and attribute as arguments to the matcher # or passing a block that reads the attribute value. # # This cop can be configured using the `EnforcedStyle` option. # # @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-rspec-2.16.0/lib/rubocop/cop/rspec/expect_in_hook.rb000066400000000000000000000022561434604127600240360ustar00rootroot00000000000000# 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_pattern('#Expectations.all') def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler 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-rspec-2.16.0/lib/rubocop/cop/rspec/expect_output.rb000066400000000000000000000032461434604127600237500ustar00rootroot00000000000000# 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) # rubocop:disable InternalAffairs/NodeDestructuring variable_name, _rhs = *node # rubocop:enable InternalAffairs/NodeDestructuring name = variable_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-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/000077500000000000000000000000001434604127600230215ustar00rootroot00000000000000rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb000066400000000000000000000076051434604127600312700ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module FactoryBot # Always declare attribute values as blocks. # # @example # # bad # kind [:active, :rejected].sample # # # good # kind { [:active, :rejected].sample } # # # bad # closed_at 1.day.from_now # # # good # closed_at { 1.day.from_now } # # # bad # count 1 # # # good # count { 1 } # class AttributeDefinedStatically < ::RuboCop::Cop::Base extend AutoCorrector MSG = 'Use a block to declare attribute values.' # @!method value_matcher(node) def_node_matcher :value_matcher, <<-PATTERN (send _ !#reserved_method? $...) PATTERN # @!method factory_attributes(node) def_node_matcher :factory_attributes, <<-PATTERN (block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } ) PATTERN def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler attributes = factory_attributes(node) || [] attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective attributes.each do |attribute| next unless offensive_receiver?(attribute.receiver, node) next if proc?(attribute) || association?(attribute.first_argument) add_offense(attribute) do |corrector| autocorrect(corrector, attribute) end end end private def autocorrect(corrector, node) if node.parenthesized? autocorrect_replacing_parens(corrector, node) else autocorrect_without_parens(corrector, node) end end def offensive_receiver?(receiver, node) receiver.nil? || receiver.self_type? || receiver_matches_first_block_argument?(receiver, node) end def receiver_matches_first_block_argument?(receiver, node) first_block_argument = node.arguments.first !first_block_argument.nil? && receiver.lvar_type? && receiver.node_parts == first_block_argument.node_parts end def proc?(attribute) value_matcher(attribute).to_a.all?(&:block_pass_type?) end # @!method association?(node) def_node_matcher :association?, '(hash <(pair (sym :factory) _) ...>)' def autocorrect_replacing_parens(corrector, node) left_braces, right_braces = braces(node) corrector.replace(node.location.begin, " #{left_braces}") corrector.replace(node.location.end, right_braces) end def autocorrect_without_parens(corrector, node) left_braces, right_braces = braces(node) argument = node.first_argument expression = argument.location.expression corrector.insert_before(expression, left_braces) corrector.insert_after(expression, right_braces) end def braces(node) if value_hash_without_braces?(node.first_argument) ['{ { ', ' } }'] else ['{ ', ' }'] end end def value_hash_without_braces?(node) node.hash_type? && !node.braces? end def reserved_method?(method_name) RuboCop::RSpec::FactoryBot.reserved_methods.include?(method_name) end def attribute_defining_method?(method_name) RuboCop::RSpec::FactoryBot.attribute_defining_methods .include?(method_name) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb000066400000000000000000000063141434604127600313640ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module FactoryBot # Use a consistent style for parentheses in factory bot calls. # # @example # # # bad # create :user # build(:user) # create(:login) # create :login # # @example `EnforcedStyle: require_parentheses` (default) # # # good # create(:user) # create(:user) # create(:login) # build(:login) # # @example `EnforcedStyle: omit_parentheses` # # # good # create :user # build :user # create :login # create :login # # # also good # # when method name and first argument are not on same line # create( # :user # ) # build( # :user, # name: 'foo' # ) # class ConsistentParenthesesStyle < ::RuboCop::Cop::Base extend AutoCorrector include ConfigurableEnforcedStyle include RuboCop::RSpec::FactoryBot::Language include RuboCop::Cop::Util def self.autocorrect_incompatible_with [Style::MethodCallWithArgsParentheses] end MSG_REQUIRE_PARENS = 'Prefer method call with parentheses' MSG_OMIT_PARENS = 'Prefer method call without parentheses' FACTORY_CALLS = RuboCop::RSpec::FactoryBot::Language::METHODS RESTRICT_ON_SEND = FACTORY_CALLS # @!method factory_call(node) def_node_matcher :factory_call, <<-PATTERN (send {#factory_bot? nil?} %FACTORY_CALLS {sym str send lvar} _* ) PATTERN def on_send(node) return if ambiguous_without_parentheses?(node) factory_call(node) do return if node.method?(:generate) && node.arguments.count > 1 if node.parenthesized? process_with_parentheses(node) else process_without_parentheses(node) end end end private def process_with_parentheses(node) return unless style == :omit_parentheses return unless same_line?(node, node.first_argument) add_offense(node.loc.selector, message: MSG_OMIT_PARENS) do |corrector| remove_parentheses(corrector, node) end end def process_without_parentheses(node) return unless style == :require_parentheses add_offense(node.loc.selector, message: MSG_REQUIRE_PARENS) do |corrector| add_parentheses(node, corrector) end end def ambiguous_without_parentheses?(node) node.parent&.send_type? || node.parent&.pair_type? || node.parent&.array_type? end def remove_parentheses(corrector, node) corrector.replace(node.location.begin, ' ') corrector.remove(node.location.end) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/create_list.rb000066400000000000000000000175471434604127600256620ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module FactoryBot # Checks for create_list usage. # # This cop can be configured using the `EnforcedStyle` option # # @example `EnforcedStyle: create_list` (default) # # bad # 3.times { create :user } # # # good # create_list :user, 3 # # # bad # 3.times { create :user, age: 18 } # # # good - index is used to alter the created models attributes # 3.times { |n| create :user, age: n } # # # good - contains a method call, may return different values # 3.times { create :user, age: rand } # # @example `EnforcedStyle: n_times` # # bad # create_list :user, 3 # # # good # 3.times { create :user } # class CreateList < ::RuboCop::Cop::Base extend AutoCorrector include ConfigurableEnforcedStyle include RuboCop::RSpec::FactoryBot::Language MSG_CREATE_LIST = 'Prefer create_list.' MSG_N_TIMES = 'Prefer %s.times.' RESTRICT_ON_SEND = %i[create_list].freeze # @!method array_new_or_n_times_block?(node) def_node_matcher :array_new_or_n_times_block?, <<-PATTERN (block { (send (const {nil? | cbase} :Array) :new (int _)) | (send (int _) :times) } ... ) PATTERN # @!method block_with_arg_and_used?(node) def_node_matcher :block_with_arg_and_used?, <<-PATTERN (block _ (args (arg _value)) `_value ) PATTERN # @!method arguments_include_method_call?(node) def_node_matcher :arguments_include_method_call?, <<-PATTERN (send ${nil? #factory_bot?} :create (sym $_) `$(send ...)) PATTERN # @!method factory_call(node) def_node_matcher :factory_call, <<-PATTERN (send ${nil? #factory_bot?} :create (sym $_) $...) PATTERN # @!method factory_list_call(node) def_node_matcher :factory_list_call, <<-PATTERN (send {nil? #factory_bot?} :create_list (sym _) (int $_) ...) PATTERN def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler return unless style == :create_list return unless array_new_or_n_times_block?(node) return if block_with_arg_and_used?(node) return unless node.body return if arguments_include_method_call?(node.body) return unless contains_only_factory?(node.body) add_offense(node.send_node, message: MSG_CREATE_LIST) do |corrector| CreateListCorrector.new(node.send_node).call(corrector) end end def on_send(node) return unless style == :n_times factory_list_call(node) do |count| message = format(MSG_N_TIMES, number: count) add_offense(node.loc.selector, message: message) do |corrector| TimesCorrector.new(node).call(corrector) end end end private def contains_only_factory?(node) if node.block_type? factory_call(node.send_node) else factory_call(node) end end # :nodoc module Corrector private def build_options_string(options) options.map(&:source).join(', ') end def format_method_call(node, method, arguments) if node.block_type? || node.parenthesized? "#{method}(#{arguments})" else "#{method} #{arguments}" end end def format_receiver(receiver) return '' unless receiver "#{receiver.source}." end end # :nodoc class TimesCorrector include Corrector def initialize(node) @node = node end def call(corrector) replacement = generate_n_times_block(node) corrector.replace(node.block_node || node, replacement) end private attr_reader :node def generate_n_times_block(node) factory, count, *options = node.arguments arguments = factory.source options = build_options_string(options) arguments += ", #{options}" unless options.empty? replacement = format_receiver(node.receiver) replacement += format_method_call(node, 'create', arguments) replacement += " #{factory_call_block_source}" if node.block_node "#{count.source}.times { #{replacement} }" end def factory_call_block_source node.block_node.location.begin.with( end_pos: node.block_node.location.end.end_pos ).source end end # :nodoc: class CreateListCorrector include Corrector def initialize(node) @node = node.parent end def call(corrector) replacement = if node.body.block_type? call_with_block_replacement(node) else call_replacement(node) end corrector.replace(node, replacement) end private attr_reader :node def call_with_block_replacement(node) block = node.body arguments = build_arguments(block, count_from(node)) replacement = format_receiver(block.receiver) replacement += format_method_call(block, 'create_list', arguments) replacement += format_block(block) replacement end def build_arguments(node, count) factory, *options = *node.send_node.arguments arguments = ":#{factory.value}, #{count}" options = build_options_string(options) arguments += ", #{options}" unless options.empty? arguments end def call_replacement(node) block = node.body factory, *options = *block.arguments arguments = "#{factory.source}, #{count_from(node)}" options = build_options_string(options) arguments += ", #{options}" unless options.empty? replacement = format_receiver(block.receiver) replacement += format_method_call(block, 'create_list', arguments) replacement end def count_from(node) count_node = if node.receiver.int_type? node.receiver else node.send_node.first_argument end count_node.source end def format_block(node) if node.body.begin_type? format_multiline_block(node) else format_singleline_block(node) end end def format_multiline_block(node) indent = ' ' * node.body.loc.column indent_end = ' ' * node.parent.loc.column " do #{node.arguments.source}\n" \ "#{indent}#{node.body.source}\n" \ "#{indent_end}end" end def format_singleline_block(node) " { #{node.arguments.source} #{node.body.source} }" end end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb000066400000000000000000000031361434604127600272050ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module FactoryBot # Use string value when setting the class attribute explicitly. # # This cop would promote faster tests by lazy-loading of # application files. Also, this could help you suppress potential bugs # in combination with external libraries by avoiding a preload of # application files from the factory files. # # @example # # bad # factory :foo, class: Foo do # end # # # good # factory :foo, class: 'Foo' do # end # class FactoryClassName < ::RuboCop::Cop::Base extend AutoCorrector MSG = "Pass '%s' string instead of `%s` " \ 'constant.' ALLOWED_CONSTANTS = %w[Hash OpenStruct].freeze RESTRICT_ON_SEND = %i[factory].freeze # @!method class_name(node) def_node_matcher :class_name, <<~PATTERN (send _ :factory _ (hash <(pair (sym :class) $(const ...)) ...>)) PATTERN def on_send(node) class_name(node) do |cn| next if allowed?(cn.const_name) msg = format(MSG, class_name: cn.const_name) add_offense(cn, message: msg) do |corrector| corrector.replace(cn, "'#{cn.source}'") end end end private def allowed?(const_name) ALLOWED_CONSTANTS.include?(const_name) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb000066400000000000000000000040611434604127600272360ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module FactoryBot # Checks for name style for argument of FactoryBot::Syntax::Methods. # # @example EnforcedStyle: symbol (default) # # bad # create('user') # build "user", username: "NAME" # # # good # create(:user) # build :user, username: "NAME" # # @example EnforcedStyle: string # # bad # create(:user) # build :user, username: "NAME" # # # good # create('user') # build "user", username: "NAME" # class FactoryNameStyle < ::RuboCop::Cop::Base extend AutoCorrector include ConfigurableEnforcedStyle include RuboCop::RSpec::FactoryBot::Language MSG = 'Use %s to refer to a factory.' FACTORY_CALLS = RuboCop::RSpec::FactoryBot::Language::METHODS RESTRICT_ON_SEND = FACTORY_CALLS # @!method factory_call(node) def_node_matcher :factory_call, <<-PATTERN (send {#factory_bot? nil?} %FACTORY_CALLS ${str sym} ... ) PATTERN def on_send(node) factory_call(node) do |name| if offense_for_symbol_style?(name) register_offense(name, name.value.to_sym.inspect) elsif offense_for_string_style?(name) register_offense(name, name.value.to_s.inspect) end end end private def offense_for_symbol_style?(name) name.str_type? && style == :symbol end def offense_for_string_style?(name) name.sym_type? && style == :string end def register_offense(name, prefer) add_offense(name, message: format(MSG, prefer: style.to_s)) do |corrector| corrector.replace(name, prefer) end end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb000066400000000000000000000046501434604127600264240ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec module FactoryBot # Use shorthands from `FactoryBot::Syntax::Methods` in your specs. # # @safety # The autocorrection is marked as unsafe because the cop # cannot verify whether you already include # `FactoryBot::Syntax::Methods` in your test suite. # # If you're using Rails, add the following configuration to # `spec/support/factory_bot.rb` and be sure to require that file in # `rails_helper.rb`: # # [source,ruby] # ---- # RSpec.configure do |config| # config.include FactoryBot::Syntax::Methods # end # ---- # # If you're not using Rails: # # [source,ruby] # ---- # RSpec.configure do |config| # config.include FactoryBot::Syntax::Methods # # config.before(:suite) do # FactoryBot.find_definitions # end # end # ---- # # @example # # bad # FactoryBot.create(:bar) # FactoryBot.build(:bar) # FactoryBot.attributes_for(:bar) # # # good # create(:bar) # build(:bar) # attributes_for(:bar) # class SyntaxMethods < Base extend AutoCorrector include InsideExampleGroup include RangeHelp include RuboCop::RSpec::FactoryBot::Language MSG = 'Use `%s` from `FactoryBot::Syntax::Methods`.' RESTRICT_ON_SEND = RuboCop::RSpec::FactoryBot::Language::METHODS def on_send(node) return unless factory_bot?(node.receiver) return unless inside_example_group?(node) message = format(MSG, method: node.method_name) add_offense(crime_scene(node), message: message) do |corrector| corrector.remove(offense(node)) end end private def crime_scene(node) range_between( node.loc.expression.begin_pos, node.loc.selector.end_pos ) end def offense(node) range_between( node.loc.expression.begin_pos, node.loc.selector.begin_pos ) end end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/file_path.rb000066400000000000000000000121741434604127600227730ustar00rootroot00000000000000# frozen_string_literal: true module RuboCop module Cop module RSpec # Checks that spec file paths are consistent and well-formed. # # By default, this checks that spec file paths are consistent with the # test subject and and enforces that it reflects the described # class/module and its optionally called out method. # # With the configuration option `IgnoreMethods` the called out method will # be ignored when determining the enforced path. # # With the configuration option `CustomTransform` modules or classes can # be specified that should not as usual be transformed from CamelCase to # snake_case (e.g. 'RuboCop' => 'rubocop' ). # # With the configuration option `SpecSuffixOnly` test files will only # be checked to ensure they end in '_spec.rb'. This option disables # checking for consistency in the test subject or test methods. # # @example # # bad # whatever_spec.rb # describe MyClass # # # bad # my_class_spec.rb # describe MyClass, '#method' # # # good # my_class_spec.rb # describe MyClass # # # good # my_class_method_spec.rb # describe MyClass, '#method' # # # good # my_class/method_spec.rb # describe MyClass, '#method' # # @example when configuration is `IgnoreMethods: true` # # bad # whatever_spec.rb # describe MyClass # # # good # my_class_spec.rb # describe MyClass # # # good # my_class_spec.rb # describe MyClass, '#method' # # @example when configuration is `SpecSuffixOnly: true` # # good # whatever_spec.rb # describe MyClass # # # good # my_class_spec.rb # describe MyClass # # # good # my_class_spec.rb # describe MyClass, '#method' # class FilePath < Base include TopLevelGroup include Namespace MSG = 'Spec path should end with `%s`.' # @!method example_group(node) def_node_matcher :example_group, <<~PATTERN (block $(send #rspec? _example_group $_ $...) ... ) PATTERN # @!method routing_metadata?(node) def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))' def on_top_level_example_group(node) return unless top_level_groups.one? example_group(node) do |send_node, example_group, arguments| ensure_correct_file_path(send_node, example_group, arguments) end end private def ensure_correct_file_path(send_node, example_group, arguments) pattern = pattern_for(example_group, arguments) return if filename_ends_with?(pattern) # For the suffix shown in the offense message, modify the regular # expression pattern to resemble a glob pattern for clearer error # messages. offense_suffix = pattern.gsub('.*', '*').sub('[^/]', '') .sub('\.', '.') add_offense(send_node, message: format(MSG, suffix: offense_suffix)) end def routing_spec?(args) args.any?(&method(:routing_metadata?)) || routing_spec_path? end def pattern_for(example_group, arguments) method_name = arguments.first if spec_suffix_only? || !example_group.const_type? || routing_spec?(arguments) return pattern_for_spec_suffix_only end [ expected_path(example_group), name_pattern(method_name), '[^/]*_spec\.rb' ].join end def pattern_for_spec_suffix_only '.*_spec\.rb' end def name_pattern(method_name) return unless method_name&.str_type? return if ignore_methods? ".*#{method_name.str_content.gsub(/\s/, '_').gsub(/\W/, '')}" end def expected_path(constant) constants = namespace(constant) + constant.const_name.split('::') File.join( constants.map do |name| custom_transform.fetch(name) { camel_to_snake_case(name) } end ) end def camel_to_snake_case(string) string .gsub(/([^A-Z])([A-Z]+)/, '\1_\2') .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2') .downcase end def custom_transform cop_config.fetch('CustomTransform', {}) end def ignore_methods? cop_config['IgnoreMethods'] end def filename_ends_with?(pattern) expanded_file_path.match?("#{pattern}$") end def relevant_rubocop_rspec_file?(_file) true end def spec_suffix_only? cop_config['SpecSuffixOnly'] end def routing_spec_path? expanded_file_path.include?('spec/routing/') end def expanded_file_path File.expand_path(processed_source.buffer.name) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/focus.rb000066400000000000000000000055041434604127600221560ustar00rootroot00000000000000# 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 # fdescribe 'test' do; end # # # good # describe '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 } 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?, send_pattern(<<~PATTERN) {#ExampleGroups.focused #Examples.focused} PATTERN def on_send(node) focus_metadata(node) do |focus| add_offense(focus) do |corrector| if focus.pair_type? || focus.str_type? || focus.sym_type? corrector.remove(with_surrounding(focus)) elsif focus.send_type? correct_send(corrector, focus) end end end end private def focus_metadata(node, &block) yield(node) if focused_block?(node) metadata(node, &block) end def with_surrounding(focus) range_with_space = range_with_surrounding_space(focus.loc.expression, 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-rspec-2.16.0/lib/rubocop/cop/rspec/hook_argument.rb000066400000000000000000000064671434604127600237120ustar00rootroot00000000000000# 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 ({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...) PATTERN # @!method unscoped_hook(node) def_node_matcher :unscoped_hook, <<-PATTERN ({block numblock} $(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| scope = implicit_style? ? '' : "(#{style.inspect})" corrector.replace(argument_range(method_send), scope) end end end alias on_numblock on_block private 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(argument_range(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 def argument_range(send_node) send_node.loc.selector.end.with( end_pos: send_node.loc.expression.end_pos ) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/hooks_before_examples.rb000066400000000000000000000040211434604127600253730ustar00rootroot00000000000000# 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 { #{block_pattern('{#ExampleGroups.all #Examples.all}')} #{numblock_pattern('{#ExampleGroups.all #Examples.all}')} #{send_pattern('#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-rspec-2.16.0/lib/rubocop/cop/rspec/identical_equality_assertion.rb000066400000000000000000000017571434604127600270050ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/implicit_block_expectation.rb000066400000000000000000000037001434604127600264220ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/implicit_expect.rb000066400000000000000000000054231434604127600242210ustar00rootroot00000000000000# 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) # rubocop:disable Metrics/MethodLength 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 is_expected_range(node.loc) when :should, :should_not node.loc.selector end end def is_expected_range(source_map) # rubocop:disable Naming/PredicateName 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-rspec-2.16.0/lib/rubocop/cop/rspec/implicit_subject.rb000066400000000000000000000104041434604127600243630ustar00rootroot00000000000000# 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') 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) 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-rspec-2.16.0/lib/rubocop/cop/rspec/instance_spy.rb000066400000000000000000000036151434604127600235370ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/instance_variable.rb000066400000000000000000000050211434604127600245020ustar00rootroot00000000000000# 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: false # # # 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-rspec-2.16.0/lib/rubocop/cop/rspec/it_behaves_like.rb000066400000000000000000000024651434604127600241570ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/iterated_expectation.rb000066400000000000000000000035761434604127600252520ustar00rootroot00000000000000# 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 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, body| if single_expectation?(body, arg) || only_expectations?(body, arg) add_offense(node.send_node) end end end def on_numblock(node) each_numblock?(node) do |body| if single_expectation?(body, :_1) || only_expectations?(body, :_1) add_offense(node.send_node) end end end private 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-rspec-2.16.0/lib/rubocop/cop/rspec/leading_subject.rb000066400000000000000000000043541434604127600241630ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/leaky_constant_declaration.rb000066400000000000000000000073251434604127600264250ustar00rootroot00000000000000# 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://relishapp.com/rspec/rspec-mocks/docs/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) add_offense(node, message: MSG_CONST) end def on_class(node) return unless inside_describe_block?(node) add_offense(node, message: MSG_CLASS) end def on_module(node) return unless inside_describe_block?(node) add_offense(node, message: MSG_MODULE) end private def inside_describe_block?(node) node.each_ancestor(:block).any?(&method(:spec_group?)) end end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/let_before_examples.rb000066400000000000000000000050321434604127600250370ustar00rootroot00000000000000# 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_pattern('{#ExampleGroups.all #Examples.all}')} #{send_pattern('#Includes.examples')} } PATTERN # @!method include_examples?(node) def_node_matcher :include_examples?, <<~PATTERN { #{block_pattern(':include_examples')} #{send_pattern(':include_examples')} } PATTERN 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-rspec-2.16.0/lib/rubocop/cop/rspec/let_setup.rb000066400000000000000000000041431434604127600230410ustar00rootroot00000000000000# 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 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?, block_pattern(<<~PATTERN) { #SharedGroups.all #ExampleGroups.all #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| 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 end end end end rubocop-rspec-2.16.0/lib/rubocop/cop/rspec/message_chain.rb000066400000000000000000000013071434604127600236220ustar00rootroot00000000000000# 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-rspec-2.16.0/lib/rubocop/cop/rspec/message_expectation.rb000066400000000000000000000032121434604127600250600ustar00rootroot00000000000000# 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 `%