diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index d3a58b2083..08cd3376b4 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ -# This file was generated on 2020-12-25T18:48:30+00:00 from the rspec-dev repo. +# This file was generated on 2023-04-16T20:53:24+01:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. github: [JonRowe, benoittgt] diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..5ace4600a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22abd9ad8f..1804471cfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,12 +8,18 @@ on: pull_request: branches: - '*' +permissions: + contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: rubocop: name: Rubocop runs-on: 'ubuntu-20.04' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: '3.0' @@ -29,21 +35,10 @@ jobs: fail-fast: false matrix: include: - # Edge Rails (7.1) builds >= 2.7 - - ruby: 3.1 - allow_failure: true - env: - RAILS_VERSION: 'main' - - ruby: '3.0' - allow_failure: true - env: - RAILS_VERSION: 'main' - - ruby: 2.7 - allow_failure: true - env: - RAILS_VERSION: 'main' - # Rails 7.0 builds >= 2.7 + - ruby: 3.2 + env: + RAILS_VERSION: '~> 7.0.0' - ruby: 3.1 env: RAILS_VERSION: '~> 7.0.0' @@ -73,7 +68,7 @@ jobs: env: ${{ matrix.env }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} diff --git a/.github/workflows/depsreview.yaml b/.github/workflows/depsreview.yaml new file mode 100644 index 0000000000..b9945082d5 --- /dev/null +++ b/.github/workflows/depsreview.yaml @@ -0,0 +1,14 @@ +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 diff --git a/.rubocop.yml b/.rubocop.yml index 95832a486d..bffff33031 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,10 @@ inherit_from: + - .rubocop_rspec_base.yml - .rubocop_todo.yml AllCops: + TargetRubyVersion: 2.5 + NewCops: disable Exclude: # Templates are really ERB which Rubocop does not parse - bin/**/* @@ -9,6 +12,18 @@ AllCops: - lib/generators/rspec/*/templates/**/* - tmp/**/* +# Over time we'd like to get this down, but this is what we're at now. +Metrics/CyclomaticComplexity: + Max: 10 # default: 6 + +# Over time we'd like to get this down, but this is what we're at now. +Layout/LineLength: + Max: 186 # default: 80 + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/MethodLength: + Max: 43 # default: 10 + Bundler/DuplicatedGem: Enabled: false @@ -17,403 +32,31 @@ Gemspec/RequiredRubyVersion: # but doesnt have a 2.2 option Enabled: false -Layout/AccessModifierIndentation: - Enabled: false - -Layout/AssignmentIndentation: - Enabled: false - -Layout/BlockAlignment: - EnforcedStyleAlignWith: start_of_block - -Layout/ClosingParenthesisIndentation: - Enabled: false - -Layout/EmptyLineAfterMagicComment: - Enabled: false - -Layout/EmptyLineBetweenDefs: - Enabled: false - -Layout/EmptyLinesAroundAccessModifier: - Enabled: false - -Layout/EmptyLinesAroundBlockBody: - Enabled: false - -Layout/ExtraSpacing: - Enabled: false - -Layout/FirstArgumentIndentation: - Enabled: false - -Layout/FirstArrayElementIndentation: - Enabled: false - -Layout/HashAlignment: - Enabled: false - -Layout/HeredocIndentation: - Enabled: false - -Layout/MultilineMethodCallBraceLayout: - Enabled: false - -Layout/MultilineMethodCallIndentation: - Enabled: false - -Layout/MultilineOperationIndentation: - Enabled: false - -Layout/ParameterAlignment: - EnforcedStyle: with_first_parameter - -Layout/SpaceInsideHashLiteralBraces: - EnforcedStyle: no_space - EnforcedStyleForEmptyBraces: no_space - -Layout/SpaceInsidePercentLiteralDelimiters: - Enabled: false - -# We use spaces, so it's less of a change to stick with that. -Layout/SpaceAroundEqualsInParameterDefault: - EnforcedStyle: space - -Layout/SpaceInsideBlockBraces: - EnforcedStyleForEmptyBraces: space - -Layout/SpaceAroundBlockParameters: - Enabled: false - -Layout/SpaceAroundOperators: - Enabled: false - -Layout/SpaceBeforeComma: - Enabled: false - -Layout/SpaceInsideStringInterpolation: - Enabled: false - -Lint/AmbiguousBlockAssociation: - Exclude: - - spec/**/* - -Lint/AmbiguousOperator: +Metrics/BlockLength: Exclude: - Rakefile + - example_app_generator/generate_app.rb + - example_app_generator/spec/**/* + - lib/rspec/rails/configuration.rb + - lib/rspec/rails/example/system_example_group.rb + - lib/rspec/rails/tasks/rspec.rake + - rspec-rails.gemspec + - spec/**/* -Lint/AmbiguousRegexpLiteral: - Exclude: - - features/step_definitions/additional_cli_steps.rb - -Lint/AssignmentInCondition: - Enabled: false - -Lint/DuplicateMethods: - Exclude: - - example_app_generator/no_active_record/app/models/in_memory/model.rb - -Lint/NonDeterministicRequireOrder: - Exclude: - - spec/spec_helper.rb - -Lint/EmptyExpression: - Enabled: false - -Lint/ImplicitStringConcatenation: - Enabled: false - -Lint/NestedMethodDefinition: - Enabled: false - -# Exceptions should be rescued with `Support::AllExceptionsExceptOnesWeMustNotRescue` -Lint/RescueException: - Enabled: true - -Lint/SuppressedException: - Exclude: - # RSpec is tightly coupled to capybara right now, this should be - # re-evaluted in the future. For now we allow the empty rescue - - lib/rspec/rails/vendor/capybara.rb - - example_app_generator/generate_stuff.rb - - example_app_generator/spec/support/default_preview_path - -Metrics/AbcSize: - Enabled: false - -Metrics/BlockLength: - Enabled: false - -# Warns when the class is excessively long. -Metrics/ClassLength: - Max: 100 - -Metrics/PerceivedComplexity: - Enabled: false - +# Offense count: 3 +# Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: Exclude: - spec/**/* -Metrics/ParameterLists: - Exclude: - - example_app_generator/spec/verify_custom_renderers_spec.rb - -# Who cares what we call the argument for binary operator methods? -Naming/BinaryOperatorParameterName: - Enabled: false - -Naming/ConstantName: - Enabled: false - -Naming/FileName: - Exclude: - # We break convention here so that when bundler requires the gem, which - # uses the gem name, things work without user configuration. - - lib/rspec-rails.rb - -Naming/HeredocDelimiterNaming: - Enabled: false - -Naming/MemoizedInstanceVariableName: - Enabled: false - -Naming/MethodParameterName: - Enabled: false - -# We have too many special cases where we allow generator methods or prefer a -# prefixed predicate due to it's improved readability. -Naming/PredicateName: - Enabled: false - -Naming/RescuedExceptionsVariableName: - Enabled: false - -Naming/VariableNumber: - Enabled: false - -Style/CollectionMethods: - PreferredMethods: - reduce: 'inject' - -Style/AccessModifierDeclarations: - Enabled: false - -# "Use alias_method instead of alias" -# We're fine with `alias`. -Style/Alias: - Enabled: false - -Style/BlockDelimiters: - Enabled: false - -# "Avoid the use of the case equality operator ===" -# We prefer using `Class#===` over `Object#is_a?` because `Class#===` -# is less likely to be monkey patched than `is_a?` on a user object. -Style/CaseEquality: - Enabled: false - -Style/ClassAndModuleChildren: - Enabled: false - -Style/ClassCheck: - Enabled: false - -Style/CommentedKeyword: - Exclude: - - spec/rspec/rails/example/view_example_group_spec.rb - -Style/ConditionalAssignment: - Enabled: false - -Style/DateTime: - Enabled: false - -# We use YARD to enforce documentation. It works better than rubocop's -# enforcement...rubocop complains about the places we re-open -# `RSpec::Expectations` and `RSpec::Matchers` w/o having doc commments. -Style/Documentation: - Enabled: false - -Style/DoubleNegation: - Enabled: false - -Style/EmptyMethod: - Enabled: false - -Style/EmptyCaseCondition: - Enabled: false - -Style/EmptyElse: - Enabled: false - -Style/FormatString: - EnforcedStyle: percent - -Style/FormatStringToken: - Enabled: false - -Style/FrozenStringLiteralComment: - Enabled: false - -Style/GlobalVars: - Exclude: - - spec/support/shared_examples.rb - -Style/GuardClause: - Enabled: false +# Override the shared base defaults that are in place for 1.8.7 support -Style/HashEachMethods: - Enabled: true +Layout/DotPosition: + EnforcedStyle: leading -Style/HashTransformKeys: - Enabled: true +Style/HashSyntax: + EnforcedStyle: ruby19 -Style/HashTransformValues: +Style/Lambda: Enabled: true -Style/IdenticalConditionalBranches: - Enabled: false - -Style/IfUnlessModifierOfIfUnless: - Enabled: false - -Style/IfInsideElse: - Enabled: false - -Style/IfUnlessModifier: - Enabled: false - -Style/MethodMissingSuper: - Enabled: false - -Style/MissingRespondToMissing: - Enabled: false - -Style/MixinUsage: - Enabled: false - -Style/MultilineIfModifier: - Enabled: false - -Style/MultipleComparison: - Enabled: false - -Style/MutableConstant: - Enabled: false - -Style/NestedModifier: - Enabled: false - -Style/NestedParenthesizedCalls: - Enabled: false - -Style/NumericLiterals: - Exclude: - - spec/rspec/rails/matchers/action_cable/have_stream_spec.rb - -Style/NumericLiteralPrefix: - EnforcedOctalStyle: zero_only - -Style/NumericPredicate: - Enabled: false - -Style/ParallelAssignment: - Enabled: false - -Style/ParenthesesAroundCondition: - Enabled: false - -Style/PercentLiteralDelimiters: - PreferredDelimiters: - '%': () # double-quoted string - '%i': '[]' # array of symbols - '%q': () # single-quoted string - '%Q': () # double-quoted string - '%r': '{}' # regular expression pattern - '%s': () # a symbol - '%w': '[]' # array of single-quoted strings - '%W': '[]' # array of double-quoted strings - '%x': () # a shell command as a string - -Style/RaiseArgs: - Exclude: - - spec/rspec/rails/matchers/be_routable_spec.rb - - spec/rspec/rails/matchers/have_rendered_spec.rb - - spec/rspec/rails/matchers/redirect_to_spec.rb - - spec/rspec/rails/matchers/route_to_spec.rb - -Style/RegexpLiteral: - Enabled: false - -Style/RedundantReturn: - Enabled: false - -Style/RedundantParentheses: - Enabled: false - -Style/RescueStandardError: - Enabled: false - -# We haven't adopted the `fail` to signal exceptions vs `raise` for re-raises convention. -Style/SignalException: - Enabled: false - -Style/SingleLineMethods: - Exclude: - - spec/rspec/rails/example/controller_example_group_spec.rb - - spec/rspec/rails/matchers/active_job_spec.rb - - spec/rspec/rails/matchers/be_a_new_spec.rb - - spec/rspec/rails/matchers/has_spec.rb - - spec/rspec/rails/matchers/have_enqueued_mail_spec.rb - - spec/rspec/rails/matchers/have_rendered_spec.rb - - spec/rspec/rails/setup_and_teardown_adapter_spec.rb - -# This rule favors constant names from the English standard library which we don't load. -Style/SpecialGlobalVars: - Enabled: false - -Style/StderrPuts: - Enabled: false - -Style/StringLiteralsInInterpolation: - Enabled: false - -Style/StructInheritance: - Enabled: false - -# We don't care about single vs double qoutes. -Style/StringLiterals: - Enabled: false - -Style/SymbolArray: - Enabled: false - -Style/SymbolProc: - Enabled: false - -Style/TernaryParentheses: - Enabled: false - -Style/TrailingCommaInArrayLiteral: - Enabled: false - -Style/TrailingCommaInHashLiteral: - Enabled: false - -Style/TrailingCommaInArguments: - Enabled: false - -Style/TrivialAccessors: - AllowDSLWriters: true - AllowPredicates: true - ExactNameMatch: true - -Style/TrailingUnderscoreVariable: - Enabled: false - -Style/YodaCondition: - Enabled: false - -Style/ZeroLengthPredicate: - Enabled: false diff --git a/.rubocop_rspec_base.yml b/.rubocop_rspec_base.yml new file mode 100644 index 0000000000..63294b1de3 --- /dev/null +++ b/.rubocop_rspec_base.yml @@ -0,0 +1,316 @@ +# This file was generated on 2022-01-10T22:24:10+00:00 from the rspec-dev repo. +# DO NOT modify it by hand as your changes will get lost the next time it is generated. + +# This file contains defaults for RSpec projects. Individual projects +# can customize by inheriting this file and overriding particular settings. + +Layout/AccessModifierIndentation: + Enabled: false + +# "Use alias_method instead of alias" +# We're fine with `alias`. +Style/Alias: + Enabled: false + +# "Avoid the use of the case equality operator ===" +# We prefer using `Class#===` over `Object#is_a?` because `Class#===` +# is less likely to be monkey patched than `is_a?` on a user object. +Style/CaseEquality: + Enabled: false + +# Warns when the class is excessively long. +Metrics/ClassLength: + Max: 100 + +Style/CollectionMethods: + PreferredMethods: + reduce: 'inject' + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/CyclomaticComplexity: + Max: 10 + +# We use YARD to enforce documentation. It works better than rubocop's +# enforcement...rubocop complains about the places we re-open +# `RSpec::Expectations` and `RSpec::Matchers` w/o having doc comments. +Style/Documentation: + Enabled: false + +# We still support 1.8.7 which requires trailing dots +Layout/DotPosition: + EnforcedStyle: trailing + +Style/DoubleNegation: + Enabled: false + +# each_with_object is unavailable on 1.8.7 so we have to disable this one. +Style/EachWithObject: + Enabled: false + +Style/FormatString: + EnforcedStyle: percent + +# As long as we support ruby 1.8.7 we have to use hash rockets. +Style/HashSyntax: + EnforcedStyle: hash_rockets + +# We can't use the new lambda syntax, since we still support 1.8.7. +Style/Lambda: + Enabled: false + +# Over time we'd like to get this down, but this is what we're at now. +Layout/LineLength: + Max: 100 + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/MethodLength: + Max: 15 + +# Who cares what we call the argument for binary operator methods? +Naming/BinaryOperatorParameterName: + Enabled: false + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + '%': () # double-quoted string + '%i': '[]' # array of symbols + '%q': () # single-quoted string + '%Q': () # double-quoted string + '%r': '{}' # regular expression pattern + '%s': () # a symbol + '%w': '[]' # array of single-quoted strings + '%W': '[]' # array of double-quoted strings + '%x': () # a shell command as a string + +# We have too many special cases where we allow generator methods or prefer a +# prefixed predicate due to it's improved readability. +Naming/PredicateName: + Enabled: false + +# On 1.8 `proc` is `lambda`, so we use `Proc.new` to ensure we get real procs on all supported versions. +# http://batsov.com/articles/2014/02/04/the-elements-of-style-in-ruby-number-12-proc-vs-proc-dot-new/ +Style/Proc: + Enabled: false + +# Exceptions should be rescued with `Support::AllExceptionsExceptOnesWeMustNotRescue` +Lint/RescueException: + Enabled: true + +# We haven't adopted the `fail` to signal exceptions vs `raise` for re-raises convention. +Style/SignalException: + Enabled: false + +# We've tended to use no space, so it's less of a change to stick with that. +Layout/SpaceAroundEqualsInParameterDefault: + EnforcedStyle: no_space + +# We don't care about single vs double qoutes. +Style/StringLiterals: + Enabled: false + +# This rule favors constant names from the English standard library which we don't load. +Style/SpecialGlobalVars: + Enabled: false + +Style/TrailingCommaInArrayLiteral: + Enabled: false + +Style/TrailingCommaInHashLiteral: + Enabled: false + +Style/TrailingCommaInArguments: + Enabled: false + +Style/TrivialAccessors: + AllowDSLWriters: true + AllowPredicates: true + ExactNameMatch: true + +Style/ParallelAssignment: + Enabled: false + +Layout/EmptyLineBetweenDefs: + Enabled: false + +Layout/FirstParameterIndentation: + Enabled: false + +Layout/ParameterAlignment: + EnforcedStyle: with_first_parameter + +Layout/SpaceInsideBlockBraces: + Enabled: false + +Layout/SpaceInsideParens: + Enabled: false + +Naming/ConstantName: + Enabled: false + +Style/ClassCheck: + Enabled: false + +Style/ConditionalAssignment: + Enabled: false + +Style/EmptyMethod: + Enabled: false + +Style/FormatStringToken: + Enabled: false + +Style/GuardClause: + Enabled: false + +Style/IdenticalConditionalBranches: + Enabled: false + +Style/IfUnlessModifier: + Enabled: false + +Style/IfUnlessModifierOfIfUnless: + Enabled: false + +Lint/MissingSuper: + Enabled: false + +Style/MissingRespondToMissing: + Enabled: false + +Style/MixinUsage: + Enabled: false + +Style/MultipleComparison: + Enabled: false + +Style/MutableConstant: + Enabled: false + +Style/NestedModifier: + Enabled: false + +Style/NestedParenthesizedCalls: + Enabled: false + +Style/NumericPredicate: + Enabled: false + +Style/RedundantParentheses: + Enabled: false + +Style/StringLiteralsInInterpolation: + Enabled: false + +Style/SymbolArray: + Enabled: false + +Style/SymbolProc: + Enabled: false + +Style/YodaCondition: + Enabled: false + +Style/ZeroLengthPredicate: + Enabled: false + +Layout/ClosingParenthesisIndentation: + Enabled: false + +Layout/ExtraSpacing: + Enabled: false + +Layout/MultilineMethodCallBraceLayout: + Enabled: false + +Layout/MultilineMethodCallIndentation: + Enabled: false + +Layout/MultilineOperationIndentation: + Enabled: false + +Layout/SpaceAroundBlockParameters: + Enabled: false + +Layout/SpaceAroundOperators: + Enabled: false + +Layout/SpaceBeforeComma: + Enabled: false + +Style/BlockDelimiters: + Enabled: false + +Style/EmptyCaseCondition: + Enabled: false + +Style/MultilineIfModifier: + Enabled: false + +Style/RescueStandardError: + Enabled: false + +Style/StderrPuts: + Enabled: false + +Style/TernaryParentheses: + Enabled: false + +Naming/HeredocDelimiterNaming: + Enabled: false + +Layout/AssignmentIndentation: + Enabled: false + +Layout/EmptyLineAfterMagicComment: + Enabled: false + +Layout/FirstArrayElementIndentation: + Enabled: false + +Layout/HeredocIndentation: + Enabled: false + +Layout/SpaceInsidePercentLiteralDelimiters: + Enabled: false + +Style/EmptyElse: + Enabled: false + +Style/IfInsideElse: + Enabled: false + +Style/RedundantReturn: + Enabled: false + +Style/StructInheritance: + Enabled: false + +Naming/VariableNumber: + Enabled: false + +Layout/SpaceInsideStringInterpolation: + Enabled: false + +Style/DateTime: + Enabled: false + +Style/ParenthesesAroundCondition: + Enabled: false + +Layout/EmptyLinesAroundBlockBody: + Enabled: false + +Lint/ImplicitStringConcatenation: + Enabled: false + +Lint/NestedMethodDefinition: + Enabled: false + +Style/RegexpLiteral: + Enabled: false + +Style/TrailingUnderscoreVariable: + Enabled: false + +Layout/EmptyLinesAroundAccessModifier: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8221da2914..d7f5923875 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,11 +1,268 @@ -# Over time we'd like to get this down, but this is what we're at now. -Metrics/CyclomaticComplexity: - Max: 9 # default: 6 +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2022-10-25 12:04:09 UTC using RuboCop version 1.28.2. +# 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. -# Over time we'd like to get this down, but this is what we're at now. -Layout/LineLength: - Max: 186 # default: 80 +# Offense count: 2 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EnforcedStyleAlignWith, Severity. +# SupportedStylesAlignWith: start_of_line, begin +Layout/BeginEndAlignment: + Exclude: + - 'lib/generators/rspec/scaffold/scaffold_generator.rb' + - 'lib/rspec/rails/tasks/rspec.rake' -# Over time we'd like to get this down, but this is what we're at now. -Metrics/MethodLength: - Max: 43 # default: 10 +# Offense count: 2 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowAliasSyntax, AllowedMethods. +# AllowedMethods: alias_method, public, protected, private +Layout/EmptyLinesAroundAttributeAccessor: + Exclude: + - 'lib/rspec/rails/adapters.rb' + - 'spec/rspec/rails/matchers/be_valid_spec.rb' + +# Offense count: 4 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'rspec-rails.gemspec' + +# Offense count: 34 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: . +# SupportedStyles: space, no_space +Layout/SpaceAroundEqualsInParameterDefault: + EnforcedStyle: space + +# Offense count: 27 +# Configuration parameters: IgnoredMethods. +Lint/AmbiguousBlockAssociation: + Exclude: + - 'spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb' + - 'spec/rspec/rails/matchers/active_job_spec.rb' + - 'spec/rspec/rails/matchers/be_a_new_spec.rb' + - 'spec/rspec/rails/matchers/have_enqueued_mail_spec.rb' + - 'spec/rspec/rails/setup_and_teardown_adapter_spec.rb' + - 'spec/rspec/rails/view_rendering_spec.rb' + - 'spec/rspec/rails/view_spec_methods_spec.rb' + +# Offense count: 1 +# This cop supports safe auto-correction (--auto-correct). +Lint/AmbiguousOperator: + Exclude: + - 'Rakefile' + +# Offense count: 5 +# This cop supports safe auto-correction (--auto-correct). +Lint/AmbiguousRegexpLiteral: + Exclude: + - 'features/step_definitions/additional_cli_steps.rb' + +# Offense count: 3 +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Exclude: + - 'lib/rspec/rails/adapters.rb' + - 'lib/rspec/rails/tasks/rspec.rake' + +# Offense count: 15 +# Configuration parameters: AllowedMethods. +# AllowedMethods: enums +Lint/ConstantDefinitionInBlock: + Exclude: + - 'example_app_generator/spec/support/default_preview_path' + - 'example_app_generator/spec/verify_custom_renderers_spec.rb' + - 'example_app_generator/spec/verify_mailer_preview_path_spec.rb' + - 'spec/rspec/rails/example/helper_example_group_spec.rb' + - 'spec/rspec/rails/example/mailer_example_group_spec.rb' + - 'spec/rspec/rails/example/view_example_group_spec.rb' + - 'spec/rspec/rails/matchers/be_valid_spec.rb' + - 'spec/rspec/rails/view_rendering_spec.rb' + - 'spec/rspec/rails/view_spec_methods_spec.rb' + +# Offense count: 1 +Lint/DuplicateMethods: + Exclude: + - 'example_app_generator/no_active_record/app/models/in_memory/model.rb' + +# Offense count: 2 +Lint/EmptyExpression: + Exclude: + - 'lib/rspec/rails/adapters.rb' + +# Offense count: 1 +# This cop supports unsafe auto-correction (--auto-correct-all). +Lint/NonDeterministicRequireOrder: + Exclude: + - 'spec/spec_helper.rb' + +# Offense count: 6 +# Configuration parameters: AllowComments, AllowNil. +Lint/SuppressedException: + Exclude: + - 'example_app_generator/generate_stuff.rb' + - 'example_app_generator/spec/support/default_preview_path' + - 'lib/rspec/rails/vendor/capybara.rb' + +# Offense count: 2 +# Configuration parameters: AllowedPatterns, IgnoredPatterns. +# AllowedPatterns: (?-mix:(exactly|at_least|at_most)\(\d+\)\.times) +Lint/UnreachableLoop: + Exclude: + - 'spec/rspec/rails/fixture_file_upload_support_spec.rb' + - 'spec/rspec/rails/fixture_support_spec.rb' + +# Offense count: 12 +# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 71 + +# Offense count: 2 +# Configuration parameters: CountKeywordArgs. +Metrics/ParameterLists: + MaxOptionalParameters: 5 + Max: 6 + +# Offense count: 3 +# Configuration parameters: IgnoredMethods. +Metrics/PerceivedComplexity: + Max: 15 + +# Offense count: 1 +# Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms. +# CheckDefinitionPathHierarchyRoots: lib, spec, test, src +# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS +Naming/FileName: + Exclude: + - 'lib/rspec-rails.rb' + +# Offense count: 7 +# Configuration parameters: EnforcedStyleForLeadingUnderscores. +# SupportedStylesForLeadingUnderscores: disallowed, required, optional +Naming/MemoizedInstanceVariableName: + Exclude: + - 'example_app_generator/generate_stuff.rb' + - 'example_app_generator/no_active_record/app/models/in_memory/model.rb' + - 'lib/generators/rspec.rb' + - 'lib/rspec/rails/matchers/have_http_status.rb' + - 'spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb' + - 'spec/rspec/rails/matchers/active_job_spec.rb' + +# Offense count: 6 +# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. +# AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to +Naming/MethodParameterName: + Exclude: + - 'benchmarks/before_block_capture_block_vs_yield.rb' + - 'lib/rspec/rails/example/routing_example_group.rb' + - 'spec/rspec/rails/example/controller_example_group_spec.rb' + +# Offense count: 4 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: PreferredName. +Naming/RescuedExceptionsVariableName: + Exclude: + - 'lib/rspec/rails/matchers/base_matcher.rb' + - 'lib/rspec/rails/matchers/have_http_status.rb' + +# Offense count: 2 +# This cop supports safe auto-correction (--auto-correct). +Style/BisectedAttrAccessor: + Exclude: + - 'lib/rspec/rails/view_rendering.rb' + +# Offense count: 18 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Enabled: false + +# Offense count: 5 +# This cop supports safe auto-correction (--auto-correct). +Style/CommentedKeyword: + Exclude: + - 'spec/rspec/rails/example/view_example_group_spec.rb' + +# Offense count: 6 +# This cop supports safe auto-correction (--auto-correct). +Style/ExplicitBlockArgument: + Exclude: + - 'benchmarks/before_block_capture_block_vs_yield.rb' + - 'features/support/env.rb' + - 'spec/sanity_check_spec.rb' + +# Offense count: 154 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Enabled: false + +# Offense count: 3 +# Configuration parameters: AllowedVariables. +Style/GlobalVars: + Exclude: + - 'spec/support/shared_examples.rb' + +# Offense count: 2 +# Configuration parameters: MinBranchesCount. +Style/HashLikeCase: + Exclude: + - 'lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb' + - 'lib/rspec/rails/matchers/active_job.rb' + +# Offense count: 4 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EnforcedOctalStyle. +# SupportedOctalStyles: zero_with_o, zero_only +Style/NumericLiteralPrefix: + Exclude: + - 'example_app_generator/generate_action_mailer_specs.rb' + - 'example_app_generator/generate_app.rb' + - 'spec/sanity_check_spec.rb' + +# Offense count: 2 +# Configuration parameters: AllowedMethods. +# AllowedMethods: respond_to_missing? +Style/OptionalBooleanParameter: + Exclude: + - 'example_app_generator/spec/verify_custom_renderers_spec.rb' + - 'lib/rspec/rails/view_rendering.rb' + +# Offense count: 23 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowIfMethodIsEmpty. +Style/SingleLineMethods: + Exclude: + - 'spec/rspec/rails/example/controller_example_group_spec.rb' + - 'spec/rspec/rails/matchers/active_job_spec.rb' + - 'spec/rspec/rails/matchers/be_a_new_spec.rb' + - 'spec/rspec/rails/matchers/has_spec.rb' + - 'spec/rspec/rails/matchers/have_enqueued_mail_spec.rb' + - 'spec/rspec/rails/matchers/have_rendered_spec.rb' + - 'spec/rspec/rails/setup_and_teardown_adapter_spec.rb' + +# Offense count: 1 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowModifier. +Style/SoleNestedConditional: + Exclude: + - 'lib/rspec/rails/tasks/rspec.rake' + +# Offense count: 4 +# This cop supports unsafe auto-correction (--auto-correct-all). +# Configuration parameters: Mode. +Style/StringConcatenation: + Exclude: + - 'lib/rspec/rails/configuration.rb' + - 'lib/rspec/rails/example/controller_example_group.rb' + - 'lib/rspec/rails/example/view_example_group.rb' + - 'spec/support/shared_examples.rb' diff --git a/BUILD_DETAIL.md b/BUILD_DETAIL.md index cd0b6ced6e..50014d9bca 100644 --- a/BUILD_DETAIL.md +++ b/BUILD_DETAIL.md @@ -1,12 +1,11 @@ # The CI build, in detail -The [Travis CI build](https://travis-ci.org/rspec/rspec-rails) -runs many verification steps to prevent regressions and +The CI build runs many verification steps to prevent regressions and ensure high-quality code. To run the Travis build locally, run: ``` @@ -50,7 +49,7 @@ project-specific threshold, the build will fail. ## Cukes RSpec uses [cucumber](https://cucumber.io/) for both acceptance testing -and [documentation](https://relishapp.com/rspec). Since we publish our cukes +and [documentation](https://rspec.info/documentation). Since we publish our cukes as documentation, please limit new cucumber scenarios to user-facing examples that help demonstrate usage. Any tests that exist purely to prevent regressions should be written as specs, even if they are written in an acceptance style. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b6be7666ce..991b9c4763 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,5 @@ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 22f5f0bb2f..41eac2cbed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ @@ -13,7 +13,7 @@ If you'd like to help make RSpec better, here are some ways you can contribute: - by running RSpec HEAD to help us catch bugs before new releases - by [reporting bugs you encounter](https://github.com/rspec/rspec-rails/issues/new?template=bug_report.md) - by [suggesting new features](https://github.com/rspec/rspec-rails/issues/new?template=feature_request.md) - - by improving RSpec's [Relish](https://relishapp.com/rspec) or [API](https://rspec.info/documentation/) documentation + - by improving RSpec's Feature or API [documentation](https://rspec.info/documentation/) - by improving [RSpec's website](https://rspec.info/) ([source](https://github.com/rspec/rspec.github.io)) - by taking part in [feature and issue discussions](https://github.com/rspec/rspec-rails/issues) - by adding a failing test for reproducible [reported bugs](https://github.com/rspec/rspec-rails/issues) diff --git a/Changelog.md b/Changelog.md index 588f32a7ee..653bb6419b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,75 @@ -### Development -[Full Changelog](https://github.com/rspec/rspec-rails/compare/v5.1.1...main) +### 6.0.4 / 2023-11-21 +[Full Changelog](https://github.com/rspec/rspec-rails/compare/v6.0.3...v6.0.4) + +Bug Fixes: + +* Fuzzy match `have_broadcasted_to` so that argument matchers can be used. + (Timothy Peraza, #2684) +* Fix fixture warning during `:context` hooks on Rails `main`. (Jon Rowe, #2685) +* Fix `stub_template` on Rails `main`. (Jon Rowe, #2685) +* Fix variable name in scaffolded view specs when namespaced. (Taketo Takashima, #2694) +* Prevent `take_failed_screenshot` producing an additional error through `metadata` + access. (Jon Rowe, #2704) +* Use `ActiveSupport::ExecutionContext::TestHelper` on Rails 7+. (Jon Rowe, #2711) +* Fix leak of templates stubbed with `stub_template` on Rails 7.1. (Jon Rowe, #2714) + +### 6.0.3 / 2023-05-31 +[Full Changelog](https://github.com/rspec/rspec-rails/compare/v6.0.2...v6.0.3) + +Bug Fixes: + +* Set `ActiveStorage::FixtureSet.file_fixture_path` when including file fixture support. + (Jason Yates, #2671) +* Allow `broadcast_to` matcher to take Symbols. (@Vagab, #2680) + +### 6.0.2 / 2023-05-04 +[Full Changelog](https://github.com/rspec/rspec-rails/compare/v6.0.1...v6.0.2) + +Bug Fixes: + +* Fix ActionView::PathSet when `render_views` is off for Rails 7.1. + (Eugene Kenny, Iliana, #2631) +* Support Rails 7.1's `#fixtures_paths` in example groups (removes a deprecation warning). + (Nicholas Simmons, #2664) +* Fix `have_enqueued_job` to properly detect enqueued jobs when other jobs were + performed inside the expectation block. (Slava Kardakov, Phil Pirozhkov, #2573) + +### 6.0.1 / 2022-10-18 +[Full Changelog](https://github.com/rspec/rspec-rails/compare/v6.0.0...v6.0.1) + +Bug Fixes: + +* Prevent tagged logged support in Rails 7 calling `#name`. (Jon Rowe, #2625) + +### 6.0.0 / 2022-10-10 +[Full Changelog](https://github.com/rspec/rspec-rails/compare/v5.1.2...v6.0.0) + +Enhancements: + +* Support Rails 7 +* Template tweaks to remove instance variables from generated specs. (Takuma Ishikawa, #2599) +* Generators now respects default path configuration option. (@vivekmiyani, #2508) + +Breaking Changes: + +* Drop support for Rails below 6.1 +* Drop support for Ruby below 2.5 (following supported versions of Rails 6.1) +* Change the order of `after_teardown` from `after` to `around` in system + specs to improve compatibility with extensions and Capybara. (Tim Diggins, #2596) + +Deprecations: + +* Deprecates integration spec generator (`rspec:integration`) + which was an alias of request spec generator (`rspec:request`) + (Luka Lüdicke, #2374) + +### 5.1.2 / 2022-04-24 +[Full Changelog](https://github.com/rspec/rspec-rails/compare/v5.1.1...v5.1.2) + +Bug Fixes: + +* Fix controller scaffold templates parameter name. (Taketo Takashima, #2591) +* Include generator specs in the inferred list of specs. (Jason Karns, #2597) ### 5.1.1 / 2022-03-07 [Full Changelog](https://github.com/rspec/rspec-rails/compare/v5.1.0...v5.1.1) @@ -74,7 +144,7 @@ Bug Fixes: Enhancements: -* Issue a warning when using job matchers with `#at` mis-match on `usec` precision. +* Issue a warning when using job matchers with `#at` mismatch on `usec` precision. (Jon Rowe, #2350) * Generated request specs now have a bare `_spec` suffix instead of `request_spec`. (Eloy Espinaco, Luka Lüdicke, #2355, #2356, #2378) @@ -201,7 +271,7 @@ Bug Fixes: Bug Fixes: -* Namespaced fixtures now generate a `/` seperated path rather than an `_`. +* Namespaced fixtures now generate a `/` separated path rather than an `_`. (@nxlith, #2077) * Check the arity of `errors` before attempting to use it to generate the `be_valid` error message. (Kevin Kuchta, #2096) @@ -361,7 +431,7 @@ Enhancements: Bug fixes: -* Prevent asset helpers from taking precendence over route helpers. (Prem Sichanugrist, #1496) +* Prevent asset helpers from taking precedence over route helpers. (Prem Sichanugrist, #1496) * Prevent `NoMethodError` during failed `have_rendered` assertions on weird templates. (Jon Rowe, #1623). diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index fd72bde592..9b33275e4f 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,5 +1,5 @@ @@ -85,9 +85,8 @@ gem declarations. The `Gemfile` evaluates that file if it exists, and it is git- # Running the build -The [Travis CI build](https://travis-ci.org/rspec/rspec-rails) -runs many verification steps to prevent regressions and -ensure high-quality code. To run the Travis build locally, run: +The CI build runs many verification steps to prevent regressions and +ensure high-quality code. To run the build locally, run: ``` $ script/run_build diff --git a/Gemfile b/Gemfile index 4ed27f8670..cd84a10b95 100644 --- a/Gemfile +++ b/Gemfile @@ -12,22 +12,12 @@ group :documentation do gem 'relish', '~> 0.7.1' end -gem 'rake', '> 12' - -if RUBY_VERSION.to_f >= 2.3 - gem 'rubocop', '~> 0.80.1' -end - gem 'capybara' - -if RUBY_VERSION.to_f >= 2.3 - gem 'ffi', '~> 1.15.5' -else - gem 'ffi', '~> 1.12.0' -end +gem 'ffi', '~> 1.15.5' +gem 'rake', '> 12' +gem 'rubocop', '~> 1.28.2' custom_gemfile = File.expand_path('Gemfile-custom', __dir__) eval_gemfile custom_gemfile if File.exist?(custom_gemfile) -eval_gemfile 'Gemfile-sqlite-dependencies' eval_gemfile 'Gemfile-rails-dependencies' diff --git a/Gemfile-rails-dependencies b/Gemfile-rails-dependencies index 1e29eb66a0..83c1e78412 100644 --- a/Gemfile-rails-dependencies +++ b/Gemfile-rails-dependencies @@ -11,15 +11,22 @@ def add_net_gems_dependency end end +# sqlite3 is an optional, unspecified, dependency and Rails 6.0 only supports `~> 1.4` +gem 'sqlite3', '~> 1.4', platforms: [:ruby] + +if RUBY_VERSION.to_f < 2.7 + gem 'puma', '< 6.0.0' +else + gem 'puma' +end + case version = ENV['RAILS_VERSION'] || (File.exist?(version_file) && File.read(version_file).chomp) || '' when /main/ gem "rails", :git => "https://github.com/rails/rails.git" - gem 'puma', "3.12.1" gem 'activerecord-jdbcsqlite3-adapter', git: 'https://github.com/jruby/activerecord-jdbc-adapter', platforms: [:jruby] gem 'selenium-webdriver', require: false when /stable$/ gem_list = %w[rails railties actionmailer actionpack activerecord activesupport activejob actionview] - gem 'puma', "3.12.1" gem 'activerecord-jdbcsqlite3-adapter', git: 'https://github.com/jruby/activerecord-jdbc-adapter', platforms: [:jruby] gem_list.each do |rails_gem| @@ -27,14 +34,12 @@ when /stable$/ end when nil, false, "" gem "rails", "~> 7.0.0" - gem "puma" gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby] gem 'selenium-webdriver', require: false else add_net_gems_dependency if version.split(' ').last < '7.0' gem "rails", version - gem "puma" gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby] gem 'selenium-webdriver', require: false end diff --git a/Gemfile-sqlite-dependencies b/Gemfile-sqlite-dependencies deleted file mode 100644 index f7ab236d64..0000000000 --- a/Gemfile-sqlite-dependencies +++ /dev/null @@ -1,20 +0,0 @@ -version_file = File.expand_path('.rails-version', __dir__) -RAILS_VERSION = ENV['RAILS_VERSION'] || (File.exist?(version_file) && File.read(version_file).chomp) || "" - -MAJOR = - case RAILS_VERSION - when /5-2-stable/ - 5 - when /main/, /stable/, nil, false, '' - 6 - else - /(\d+)[\.|-]\d+/.match(RAILS_VERSION).captures.first.to_i - end - -if MAJOR >= 6 -# sqlite3 is an optional, unspecified, dependency and Rails 6.0 only supports `~> 1.4` - gem 'sqlite3', '~> 1.4', platforms: [:ruby] -else -# Similarly, Rails 5.0 only supports '~> 1.3.6'. Rails 5.1-5.2 support '~> 1.3', '>= 1.3.6' - gem 'sqlite3', '~> 1.3.6', platforms: [:ruby] -end diff --git a/README.md b/README.md index 09ed156aa2..7c7098fa0f 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,6 @@ According to [RSpec Rails new versioning strategy][] use: * **[`rspec-rails` 3.x][]** for Rails earlier than 5.0. * **[`rspec-rails` 1.x][]** for Rails 2.x. -[Build Status]: https://secure.travis-ci.org/rspec/rspec-rails.svg?branch=main -[travis-ci]: https://travis-ci.org/rspec/rspec-rails [Code Climate]: https://codeclimate.com/github/rspec/rspec-rails.svg [code-climate]: https://codeclimate.com/github/rspec/rspec-rails [Gem Version]: https://badge.fury.io/rb/rspec-rails.svg @@ -88,8 +86,8 @@ read the [`rspec-rails` upgrade notes][] to find out what to watch out for. Be sure to check the general [RSpec upgrade notes][] as well. -[`rspec-rails` upgrade notes]: https://www.relishapp.com/rspec/rspec-rails/docs/upgrade -[RSpec upgrade notes]: https://relishapp.com/rspec/docs/upgrade +[`rspec-rails` upgrade notes]: https://rspec.info/features/6-0/rspec-rails/upgrade +[RSpec upgrade notes]: https://rspec.info/upgrading-from-rspec-2/ ## Usage @@ -183,7 +181,7 @@ rspec ./spec/models/post_spec.rb:3 # Post before publication cannot have comment For an in-depth look at the RSpec DSL, including lots of examples, read the official Cucumber documentation for [RSpec Core][]. -[RSpec Core]: https://relishapp.com/rspec/rspec-core/docs +[RSpec Core]: https://rspec.info/features/3-12/rspec-core ### Helpful Rails Matchers @@ -209,23 +207,23 @@ to test the various parts of a Rails system: Follow the links above for examples of how each matcher is used. -[the matchers that come standard in RSpec]: https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers -[`be_a_new`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/be-a-new-matcher -[`render_template`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/render-template-matcher -[`redirect_to`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/redirect-to-matcher -[`route_to`]: https://relishapp.com/rspec/rspec-rails/docs/routing-specs/route-to-matcher -[`be_routable`]: https://relishapp.com/rspec/rspec-rails/docs/routing-specs/be-routable-matcher -[`have_http_status`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/have-http-status-matcher -[`match_array`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/activerecord-relation-match-array -[`have_been_enqueued`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/have-been-enqueued-matcher -[`have_enqueued_job`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/have-enqueued-job-matcher +[the matchers that come standard in RSpec]: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers +[`be_a_new`]: https://rspec.info/features/6-0/rspec-rails/matchers/new-record-matcher +[`render_template`]: https://rspec.info/features/6-0/rspec-rails/matchers/render-template-matcher +[`redirect_to`]: https://rspec.info/features/6-0/rspec-rails/matchers/redirect-to-matcher +[`route_to`]: https://rspec.info/features/6-0/rspec-rails/routing-specs/route-to-matcher +[`be_routable`]: https://rspec.info/features/6-0/rspec-rails/routing-specs/be-routable-matcher +[`have_http_status`]: https://rspec.info/features/6-0/rspec-rails/matchers/have-http-status-matcher +[`match_array`]: https://rspec.info/features/6-0/rspec-rails/matchers/relation-match-array +[`have_been_enqueued`]: https://rspec.info/features/6-0/rspec-rails/matchers/have-been-enqueued-matcher +[`have_enqueued_job`]: https://rspec.info/features/6-0/rspec-rails/matchers/have-enqueued-job-matcher ### What else does RSpec Rails add? For a comprehensive look at RSpec Rails’ features, read the [official Cucumber documentation][]. -[official Cucumber documentation]: https://relishapp.com/rspec/rspec-rails/docs +[official Cucumber documentation]: https://rspec.info/features/6-0/rspec-rails ## What tests should I write? @@ -270,20 +268,20 @@ RSpec.describe User, type: :model do ... ``` -[request]: https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec -[feature]: https://www.relishapp.com/rspec/rspec-rails/docs/feature-specs/feature-spec -[system]: https://relishapp.com/rspec/rspec-rails/docs/system-specs/system-spec -[model]: https://www.relishapp.com/rspec/rspec-rails/docs/model-specs -[controller]: https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs -[mailer]: https://relishapp.com/rspec/rspec-rails/docs/mailer-specs -[job]: https://relishapp.com/rspec/rspec-rails/docs/job-specs/job-spec -[view]: https://www.relishapp.com/rspec/rspec-rails/docs/view-specs/view-spec -[routing]: https://www.relishapp.com/rspec/rspec-rails/docs/routing-specs -[helper]: https://www.relishapp.com/rspec/rspec-rails/docs/helper-specs/helper-spec +[request]: https://rspec.info/features/6-0/rspec-rails/request-specs/request-spec +[feature]: https://rspec.info/features/6-0/rspec-rails/feature-specs/feature-spec +[system]: https://rspec.info/features/6-0/rspec-rails/system-specs/system-specs +[model]: https://rspec.info/features/6-0/rspec-rails/model-specs +[controller]: https://rspec.info/features/6-0/rspec-rails/controller-specs +[mailer]: https://rspec.info/features/6-0/rspec-rails/mailer-specs +[job]: https://rspec.info/features/6-0/rspec-rails/job-specs/job-spec +[view]: https://rspec.info/features/6-0/rspec-rails/view-specs/view-spec +[routing]: https://rspec.info/features/6-0/rspec-rails/routing-specs +[helper]: https://rspec.info/features/6-0/rspec-rails/helper-specs/helper-spec [`ActionDispatch::IntegrationTest`]: https://api.rubyonrails.org/classes/ActionDispatch/IntegrationTest.html [`ActionDispatch::SystemTestCase`]: https://api.rubyonrails.org/classes/ActionDispatch/SystemTestCase.html [`ActionController::TestCase`]: https://api.rubyonrails.org/classes/ActionController/TestCase.html -[in the appropriate folder]: https://relishapp.com/rspec/rspec-rails/docs/directory-structure +[in the appropriate folder]: https://rspec.info/features/6-0/rspec-rails/directory-structure ### System specs, feature specs, request specs–what’s the difference? @@ -366,10 +364,10 @@ you can run the specs and Cucumber features, or submit a pull request. ### RSpec base libraries -* -* -* -* +* https://github.com/rspec/rspec +* https://github.com/rspec/rspec-core +* https://github.com/rspec/rspec-expectations +* https://github.com/rspec/rspec-mocks ### Recommended third-party extensions diff --git a/README_DEV.md b/README_DEV.md index 8c01e824e0..b9ea3c98c1 100644 --- a/README_DEV.md +++ b/README_DEV.md @@ -34,6 +34,6 @@ Rails than you are trying to use now. To run the specs against a different version of Rails, use the `thor` command: ```bash -bin/thor version:use 6.0.2.2 +bin/thor version:use 7.0.3.1 bin/rake ``` diff --git a/Rakefile b/Rakefile index 945753c0f0..77d282a72d 100644 --- a/Rakefile +++ b/Rakefile @@ -95,6 +95,11 @@ end namespace :smoke do desc "create a new example app with generated specs and run them" task app: ["clobber:app", "generate:app", "generate:stuff", :smoke] + + desc "run RSPEC_OPTS environment variable in the example app for local dev" + task :rspec do + in_example_app "LOCATION='../../example_app_generator/run_specs.rb' bin/rspec #{ENV.fetch("RSPEC_OPTS")}" + end end desc 'clobber generated files' @@ -112,20 +117,6 @@ namespace :clobber do end end -desc "Push docs/cukes to relishapp using the relish-client-gem" -task :relish, :version do |_t, args| - raise "rake relish[VERSION]" unless args[:version] - - sh "cp Changelog.md features/" - if `relish versions rspec/rspec-rails`.split.map(&:strip).include? args[:version] - puts "Version #{args[:version]} already exists" - else - sh "relish versions:add rspec/rspec-rails:#{args[:version]}" - end - sh "relish push rspec/rspec-rails:#{args[:version]}" - sh "rm features/Changelog.md" -end - namespace :no_active_record do example_app_dir = './tmp/no_ar_example_app' @@ -143,6 +134,11 @@ namespace :no_active_record do "no_active_record:generate:stuff", "no_active_record:smoke", ] + + desc "run RSPEC_OPTS environment variable in the example app for local dev" + task :rspec do + in_example_app "LOCATION='../../example_app_generator/run_specs.rb' bin/rspec #{ENV.fetch("RSPEC_OPTS")}", app_dir: example_app_dir + end end desc "remove the old non-ActiveRecord app" diff --git a/appveyor.yml b/appveyor.yml index e94a6e2e00..c022c1bf24 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,9 +3,9 @@ version: "{build}" -# This will build all PRs targetting matching branches. +# This will build all PRs targeting matching branches. # Without this, each PR builds twice -- once for the PR branch HEAD, -# and once for the merge commit that github creates for each mergable PR. +# and once for the merge commit that github creates for each mergeable PR. branches: only: - main diff --git a/benchmarks/before_block_capture_block_vs_yield.rb b/benchmarks/before_block_capture_block_vs_yield.rb index 254be135ae..e294c06834 100644 --- a/benchmarks/before_block_capture_block_vs_yield.rb +++ b/benchmarks/before_block_capture_block_vs_yield.rb @@ -36,7 +36,7 @@ def capture_block_and_call_n_times(n, &block) __END__ -This attemps to measure the performance of how `routes` works in RSpec. It's +This attempts to measure the performance of how `routes` works in RSpec. It's actually a method which delegates to `before`. RSpec executes `before` hooks by capturing the block and then performing an `instance_exec` on it later in the example context. @@ -54,7 +54,7 @@ def capture_block_and_call_n_times(n, &block) > a high constant cost, taking about 5x longer than a single `yield` > (even if the block is never used!). > -> However, fowarding a captured block can be faster than using `yield` +> However, forwarding a captured block can be faster than using `yield` > if the block is used many times (the breakeven point is at about 20-25 > invocations), so it appears that he per-invocation cost of `yield` > is higher than that of a captured-and-forwarded block. @@ -71,7 +71,7 @@ def capture_block_and_call_n_times(n, &block) > Surprisingly, `flat_map(&block)` appears to be faster than > `flat_map { yield }` in spite of the fact that our array here > is smaller than the break-even point of 20-25 measured in the -> `capture_block_vs_yield.rb` benchmark. In fact, the forwaded-block +> `capture_block_vs_yield.rb` benchmark. In fact, the forwarded-block > version remains faster in my benchmarks here no matter how small > I shrink the `words` array. I'm not sure why! > diff --git a/cucumber.yml b/cucumber.yml index 161eaa7c36..bfcd976ea1 100644 --- a/cucumber.yml +++ b/cucumber.yml @@ -1,3 +1,3 @@ -default: --require features --format progress --tags 'not @wip' -pretty: --require features --format pretty --tags 'not @wip' -wip: --require features --tags @wip +default: --publish-quiet --require features --format progress --tags 'not @wip' +pretty: --publish-quiet --require features --format pretty --tags 'not @wip' +wip: --publish-quiet --require features --tags @wip diff --git a/example_app_generator/app/views/_example.html.erb b/example_app_generator/app/views/_example.html.erb new file mode 100644 index 0000000000..683d678ac3 --- /dev/null +++ b/example_app_generator/app/views/_example.html.erb @@ -0,0 +1 @@ +TEMPLATE_HTML diff --git a/example_app_generator/config/initializers/sqlite3_fix.rb b/example_app_generator/config/initializers/sqlite3_fix.rb deleted file mode 100644 index 96ea148ac4..0000000000 --- a/example_app_generator/config/initializers/sqlite3_fix.rb +++ /dev/null @@ -1,3 +0,0 @@ -if Rails.application.config.respond_to?(:active_record) && RUBY_ENGINE != "jruby" - Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true -end diff --git a/example_app_generator/generate_action_mailer_specs.rb b/example_app_generator/generate_action_mailer_specs.rb index b66f052f49..16959ee81a 100644 --- a/example_app_generator/generate_action_mailer_specs.rb +++ b/example_app_generator/generate_action_mailer_specs.rb @@ -15,12 +15,7 @@ end CODE - rails_parent = - if Rails.version.to_f >= 6.0 - Rails.application.class.module_parent.to_s - else - Rails.application.class.parent.to_s - end + rails_parent = Rails.application.class.module_parent.to_s gsub_file 'config/initializers/action_mailer.rb', /ExampleApp/, rails_parent diff --git a/example_app_generator/generate_app.rb b/example_app_generator/generate_app.rb index 08ecbf2f65..4b2c539d5c 100644 --- a/example_app_generator/generate_app.rb +++ b/example_app_generator/generate_app.rb @@ -11,7 +11,6 @@ 'ci_retry_bundle_install.sh' ) function_script_file = File.join(rspec_rails_repo_path, 'script/functions.sh') -sqlite_initializer = File.join(rspec_rails_repo_path, "example_app_generator/config/initializers/sqlite3_fix.rb") in_root do prepend_to_file "Rakefile", "require 'active_support/all'" @@ -19,7 +18,7 @@ # Remove the existing rails version so we can properly use main or other # edge branches gsub_file 'Gemfile', /^.*\bgem ['"]rails.*$/, '' - gsub_file 'Gemfile', /^.*\bgem ['"]selenium\-webdriver.*$/, '' + gsub_file 'Gemfile', /^.*\bgem ['"]selenium-webdriver.*$/, '' gsub_file "Gemfile", /.*web-console.*/, '' gsub_file "Gemfile", /.*debug.*/, '' gsub_file "Gemfile", /.*puma.*/, '' @@ -27,31 +26,13 @@ append_to_file 'Gemfile', "gem 'rails-controller-testing'\n" - if Rails::VERSION::STRING >= '6' - gsub_file "Gemfile", /.*rails-controller-testing.*/, "gem 'rails-controller-testing', git: 'https://github.com/rails/rails-controller-testing'" + gsub_file "Gemfile", /.*rails-controller-testing.*/, "gem 'rails-controller-testing', git: 'https://github.com/rails/rails-controller-testing'" - # TODO: To remove when Rails released with https://github.com/rails/rails/pull/40281 - append_to_file 'Gemfile', <<-EOT.gsub(/^ +\|/, '') - |gem 'rexml' - EOT - end - - if Rails::VERSION::STRING >= '6' - # sqlite3 is an optional, unspecified, dependency and Rails 6.0 only supports `~> 1.4` - gsub_file "Gemfile", /.*gem..sqlite3.*/, "gem 'sqlite3', '~> 1.4'" - else - # Similarly, Rails 5.0 only supports '~> 1.3.6'. Rails 5.1-5.2 support '~> 1.3', '>= 1.3.6' - gsub_file "Gemfile", /.*gem..sqlite3.*/, "gem 'sqlite3', '~> 1.3.6'" - end + # sqlite3 is an optional, unspecified, dependency and Rails 6.0 only supports `~> 1.4` + gsub_file "Gemfile", /.*gem..sqlite3.*/, "gem 'sqlite3', '~> 1.4'" - # webdrivers 4 up until 4.3.0 don't specify `required_ruby_version`, but contain - # Ruby 2.2-incompatible syntax (safe navigation). - # That basically means we use pre-4.0 for Ruby 2.2, and 4.3+ for newer Rubies. - gsub_file "Gemfile", /.*chromedriver-helper.*/, "gem 'webdrivers', '!= 4.0.0', '!= 4.0.1', '!= 4.1.0', '!= 4.1.1', '!= 4.1.2', '!= 4.1.3', '!= 4.2.0'" - - if Rails::VERSION::STRING < '6' - copy_file sqlite_initializer, 'config/initializers/sqlite3_fix.rb' - end + # remove webdrivers + gsub_file "Gemfile", /gem ['"]webdrivers['"]/, "" if RUBY_ENGINE == "jruby" gsub_file "Gemfile", /.*jdbc.*/, '' diff --git a/example_app_generator/generate_stuff.rb b/example_app_generator/generate_stuff.rb index 2431720d62..5448587fb6 100644 --- a/example_app_generator/generate_stuff.rb +++ b/example_app_generator/generate_stuff.rb @@ -14,10 +14,12 @@ def setup_tasks def final_tasks copy_file 'spec/verify_active_record_spec.rb' + copy_file 'app/views/_example.html.erb' copy_file 'app/views/foo.html' copy_file 'app/views/some_templates/bar.html' copy_file 'spec/verify_custom_renderers_spec.rb' copy_file 'spec/verify_fixture_warning_spec.rb' + copy_file 'spec/verify_view_path_stub_spec.rb' run('bin/rake db:migrate') end @@ -89,7 +91,7 @@ def using_source_path(path) # request specs are now the default generate('rspec:controller wombats --no-request-specs --controller-specs --no-view-specs') -generate('integration_test widgets') +generate('integration_test widgets') # deprecated generate('mailer Notifications signup') generate('model thing name:string') diff --git a/example_app_generator/no_active_record/app/models/in_memory/model.rb b/example_app_generator/no_active_record/app/models/in_memory/model.rb index 9b440e2c72..f9c59143d9 100644 --- a/example_app_generator/no_active_record/app/models/in_memory/model.rb +++ b/example_app_generator/no_active_record/app/models/in_memory/model.rb @@ -72,11 +72,13 @@ def save(*) self.class.all << self true end + alias :save! :save def destroy self.class.all.delete(self) true end + alias :destroy! :destroy def reload(*) self diff --git a/example_app_generator/no_active_record/config/initializers/zeitwerk.rb b/example_app_generator/no_active_record/config/initializers/zeitwerk.rb new file mode 100644 index 0000000000..b78def42e3 --- /dev/null +++ b/example_app_generator/no_active_record/config/initializers/zeitwerk.rb @@ -0,0 +1,3 @@ +if Rails.autoloaders.respond_to?(:main) && Rails.autoloaders.main.respond_to?(:ignore) + Rails.autoloaders.main.ignore('lib/rails/generators/in_memory/model/model_generator.rb') +end diff --git a/example_app_generator/spec/support/default_preview_path b/example_app_generator/spec/support/default_preview_path index 3d64f7487b..5d535156e9 100755 --- a/example_app_generator/spec/support/default_preview_path +++ b/example_app_generator/spec/support/default_preview_path @@ -26,11 +26,9 @@ require_file_stub 'config/environment' do require "action_controller/railtie" require "action_mailer/railtie" unless ENV['NO_ACTION_MAILER'] require "action_view/railtie" - if Rails::VERSION::STRING >= '6' - require "action_cable/engine" - require "active_job/railtie" - require "action_mailbox/engine" - end + require "action_cable/engine" + require "active_job/railtie" + require "action_mailbox/engine" # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -39,10 +37,12 @@ require_file_stub 'config/environment' do module ExampleApp class Application < Rails::Application config.eager_load = false + if Rails::VERSION::STRING.to_f >= 7.0 + config.active_support.cache_format_version = 7.0 + end # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false unless ENV['NO_ACTION_MAILER'] - if ENV['CUSTOM_PREVIEW_PATH'] config.action_mailer.preview_path = ENV['CUSTOM_PREVIEW_PATH'] end @@ -50,7 +50,7 @@ require_file_stub 'config/environment' do config.action_mailer.show_previews = (ENV['SHOW_PREVIEWS'] == 'true') end - config.active_record.legacy_connection_handling = false if Rails::VERSION::STRING >= '7' + config.active_record.legacy_connection_handling = false if Rails::VERSION::STRING.start_with?('7.0') end end @@ -61,13 +61,18 @@ require_file_stub 'config/environment' do Rails.application.initialize! end -exit if ENV['NO_ACTION_MAILER'] +exit(0) if ENV['NO_ACTION_MAILER'] if ENV['DEFAULT_URL'] puts ActionMailer::Base.default_url_options[:host] elsif defined?(::ActionMailer::Preview) - puts Rails.application.config.action_mailer.preview_path + if Rails::VERSION::STRING.start_with?('7.1') + puts Rails.application.config.action_mailer.preview_paths + else + puts Rails.application.config.action_mailer.preview_path + end end # This will force the loading of ActionMailer settings to ensure we do not -# accicentally set something we should not +# accidentally set something we should not ActionMailer::Base.smtp_settings +exit 0 diff --git a/example_app_generator/spec/verify_custom_renderers_spec.rb b/example_app_generator/spec/verify_custom_renderers_spec.rb index 2edab4b91c..f52b03dc94 100644 --- a/example_app_generator/spec/verify_custom_renderers_spec.rb +++ b/example_app_generator/spec/verify_custom_renderers_spec.rb @@ -36,12 +36,6 @@ def index expect(response).to render_template(:bar) end - - it "renders an empty string", skip: Rails::VERSION::STRING.to_f >= 6.0 do - get :index - - expect(response.body).to eq("") - end end context "with a custom renderer prepended to the view path" do diff --git a/example_app_generator/spec/verify_mailer_preview_path_spec.rb b/example_app_generator/spec/verify_mailer_preview_path_spec.rb index 96bfaee787..6046210730 100644 --- a/example_app_generator/spec/verify_mailer_preview_path_spec.rb +++ b/example_app_generator/spec/verify_mailer_preview_path_spec.rb @@ -16,10 +16,18 @@ def as_commandline(ops) end def capture_exec(*ops) - ops << {err: [:child, :out]} - io = IO.popen(ops) + ops << { err: [:child, :out] } + lines = [] + + _process = + IO.popen(ops) do |io| + while (line = io.gets) + lines << line + end + end + # Necessary to ignore warnings from Rails code base - out = io.readlines + out = lines .reject { |line| line =~ /warning: circular argument reference/ } .reject { |line| line =~ /Gem::Specification#rubyforge_project=/ } .reject { |line| line =~ /DEPRECATION WARNING/ } @@ -30,7 +38,16 @@ def capture_exec(*ops) CaptureExec.new(out, $?.exitstatus) end - def have_no_preview + if ENV['RAILS_VERSION'] == 'main' && Rails::VERSION::STRING == "7.2.0.alpha" + before do + skip('This is broken on Rails main but is skipped for green builds of 7.1.x, please fix') + end + end + + let(:expected_custom_path) { '/custom/path' } + let(:expected_rspec_path) { "#{::Rails.root}/spec/mailers/previews" } + + def have_no_preview(_opts = {}) have_attributes(io: be_blank, exit_status: 0) end @@ -40,14 +57,12 @@ def have_no_preview if RSpec::Rails::FeatureCheck.has_action_mailer_preview? context 'in the development environment' do - let(:custom_env) { {'RAILS_ENV' => rails_env} } + let(:custom_env) { { 'RAILS_ENV' => rails_env } } let(:rails_env) { 'development' } it 'sets the preview path to the default rspec path' do skip "this spec fails singularly on JRuby due to weird env things" if RUBY_ENGINE == "jruby" - expect(capture_exec(custom_env, exec_script)).to eq( - "#{::Rails.root}/spec/mailers/previews" - ) + expect(capture_exec(custom_env, exec_script)).to eq(expected_rspec_path) end it 'respects the setting from `show_previews`' do @@ -65,7 +80,7 @@ def have_no_preview custom_env.merge('CUSTOM_PREVIEW_PATH' => '/custom/path'), exec_script ) - ).to eq('/custom/path') + ).to eq(expected_custom_path) end it 'allows initializers to set options' do @@ -83,12 +98,12 @@ def have_no_preview custom_env.merge('NO_ACTION_MAILER' => 'true'), exec_script ) - ).to have_no_preview + ).to have_no_preview(actually_blank: true) end end context 'in a non-development environment' do - let(:custom_env) { {'RAILS_ENV' => rails_env} } + let(:custom_env) { { 'RAILS_ENV' => rails_env } } let(:rails_env) { 'test' } it 'does not set the preview path by default' do @@ -98,7 +113,7 @@ def have_no_preview it 'respects the setting from `show_previews`' do expect( capture_exec(custom_env.merge('SHOW_PREVIEWS' => 'true'), exec_script) - ).to eq("#{::Rails.root}/spec/mailers/previews") + ).to eq(expected_rspec_path) end it 'allows initializers to set options' do @@ -123,7 +138,7 @@ def have_no_preview end else context 'in the development environment' do - let(:custom_env) { {'RAILS_ENV' => rails_env} } + let(:custom_env) { { 'RAILS_ENV' => rails_env } } let(:rails_env) { 'development' } it 'handles no action mailer preview' do @@ -150,7 +165,7 @@ def have_no_preview end context 'in a non-development environment' do - let(:custom_env) { {'RAILS_ENV' => rails_env} } + let(:custom_env) { { 'RAILS_ENV' => rails_env } } let(:rails_env) { 'test' } it 'handles no action mailer preview' do diff --git a/example_app_generator/spec/verify_view_path_stub_spec.rb b/example_app_generator/spec/verify_view_path_stub_spec.rb new file mode 100644 index 0000000000..60a9d4110d --- /dev/null +++ b/example_app_generator/spec/verify_view_path_stub_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +RSpec.describe "verify view path doesnt leak stubs between examples", type: :view, order: :defined do + subject(:html) do + render partial: "example" + rendered + end + + it "renders the stub template" do + stub_template("_example.html.erb" => "STUB_HTML") + expect(html).to include("STUB_HTML") + end + + it "renders the file template" do + expect(html).to include("TEMPLATE_HTML") + end +end diff --git a/features/.nav b/features/.nav index 7afd8ad003..0af57bfb15 100644 --- a/features/.nav +++ b/features/.nav @@ -1,8 +1,6 @@ - GettingStarted.md (Start from scratch) - Generators.md (Generators) - Transactions.md -- Changelog.md -- RailsVersions.md (Rails versions) - directory_structure.feature - backtrace_filtering.feature - model_specs: @@ -11,7 +9,7 @@ - mock_model.feature - stub_model.feature - controller_specs: - - Cookies.md + - cookies.feature - controller_spec.feature - isolation_from_views.feature - render_views.feature diff --git a/features/Generators.md b/features/Generators.md index e85536ec90..f3a6ef2f1b 100644 --- a/features/Generators.md +++ b/features/Generators.md @@ -1,3 +1,5 @@ +# Using generators + RSpec spec are normally generated alongside other application components. For instance, `rails generate model` will also generate an RSpec spec file for the model. diff --git a/features/GettingStarted.md b/features/GettingStarted.md index 7fc720cb4c..7e251ed6e4 100644 --- a/features/GettingStarted.md +++ b/features/GettingStarted.md @@ -1,3 +1,5 @@ +# Getting Started + Install Rails 6 $ gem install rails -v "~> 6.0.0" @@ -7,7 +9,7 @@ Install Rails 6 $ rails new example_app $ cd example_app -### Add rspec-rails to the Gemfile +### Add `rspec-rails` to the Gemfile $ echo 'gem "rspec-rails", group: [:development, :test]' >> Gemfile diff --git a/features/README.md b/features/README.md index d908df11fc..5fb816609c 100644 --- a/features/README.md +++ b/features/README.md @@ -1,12 +1,16 @@ -rspec-rails extends Rails' built-in testing framework to support rspec +# RSpec Rails + +`rspec-rails` extends Rails' built-in testing framework to support rspec examples for requests, controllers, models, views, helpers, mailers and -routing. +routing. It is a thin framework around Rails own helpers and you can +check their documentation for help as well. ## Rails -rspec-rails 5 supports Rails 5.2 to 6.1. For earlier versions of Rails, you -should use [rspec-rails-4](https://github.com/rspec/rspec-rails/tree/4-1-maintenance) -for Rails 5.x and [rspec-rails 3](https://github.com/rspec/rspec-rails/tree/3-9-maintenance) +rspec-rails 6 supports Rails 6.1 to 7.0. For earlier versions of Rails, you +should use [rspec-rails-5](https://github.com/rspec/rspec-rails/tree/5-1-maintenance) +for Rails 5.2 and 6.0, [rspec-rails-4](https://github.com/rspec/rspec-rails/tree/4-1-maintenance) +for Rails 5.x, and [rspec-rails 3](https://github.com/rspec/rspec-rails/tree/3-9-maintenance) for even older versions. ## Install @@ -26,7 +30,7 @@ This installs the following gems: Add rspec-rails to the :test and :development groups in the Gemfile: group :test, :development do - gem 'rspec-rails', '~> 5.0.0' + gem 'rspec-rails', '~> 6.0.0' end It needs to be in the :development group to expose generators and rake tasks @@ -34,11 +38,15 @@ without having to type RAILS_ENV=test. Now you can run: - script/rails generate rspec:install + bundle exec rails generate rspec:install This adds the spec directory and some skeleton files, including a .rspec file. +You can also customize the default spec path with `--default-path` option: + + bundle exec rails generate rspec:install --default-path behaviour + ## Issues The documentation for rspec-rails is a work in progress. We'll be adding diff --git a/features/RailsVersions.md b/features/RailsVersions.md deleted file mode 100644 index cd1abcc5b7..0000000000 --- a/features/RailsVersions.md +++ /dev/null @@ -1,13 +0,0 @@ - rails version | rspec-rails version - ------------- | ------------------- - 2.3 | 1.3.4 - 3.0 | >= 2.0 - 3.1 | >= 2.6 - 3.2 | >= 2.9 - 4.0 | >= 2.14 - 4.1 | >= 3.0 - 4.2 | >= 3.1 - 5.0 | >= 3.5 - 5.1 | >= 3.6 - 5.2 | >= 3.8 - 6.0 | >= 4.0 diff --git a/features/Transactions.md b/features/Transactions.md index 634462eba5..8dfc8cf55d 100644 --- a/features/Transactions.md +++ b/features/Transactions.md @@ -1,3 +1,5 @@ +# Transactions + When you run `rails generate rspec:install`, the `spec/rails_helper.rb` file includes the following configuration: diff --git a/features/backtrace_filtering.feature b/features/backtrace_filtering.feature index f4e5ddac39..58ef798022 100644 --- a/features/backtrace_filtering.feature +++ b/features/backtrace_filtering.feature @@ -1,4 +1,4 @@ -Feature: backtrace filtering +Feature: Backtrace filtering The following configuration setting will filter out lines in backtraces that come from Rails gems in order to reduce the noise in test failure output: @@ -21,7 +21,7 @@ Feature: backtrace filtering config.filter_rails_from_backtrace! end - RSpec.describe "Controller", :type => :controller do + RSpec.describe "Controller", type: :controller do controller do def index raise "Something went wrong." diff --git a/features/channel_specs/channel_spec.feature b/features/channel_specs/channel_spec.feature index 3c48fdd7b2..aa38326ff6 100644 --- a/features/channel_specs/channel_spec.feature +++ b/features/channel_specs/channel_spec.feature @@ -1,7 +1,6 @@ -@rails_post_6 -Feature: channel spec +Feature: Channel specs - Channel specs are marked by `:type => :channel` or if you have set + Channel specs are marked by `type: :channel` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/channels`. A channel spec is a thin wrapper for an `ActionCable::Channel::TestCase`, and includes all @@ -33,12 +32,12 @@ Feature: channel spec end """ - Scenario: simple passing example + Scenario: A simple passing example Given a file named "spec/channels/chat_channel_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ChatChannel, :type => :channel do + RSpec.describe ChatChannel, type: :channel do it "successfully subscribes" do subscribe room_id: 42 expect(subscription).to be_confirmed @@ -48,12 +47,12 @@ Feature: channel spec When I run `rspec spec/channels/chat_channel_spec.rb` Then the example should pass - Scenario: verifying that subscription is rejected + Scenario: Verifying that a subscription is rejected Given a file named "spec/channels/chat_channel_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ChatChannel, :type => :channel do + RSpec.describe ChatChannel, type: :channel do it "rejects subscription" do subscribe room_id: nil expect(subscription).to be_rejected @@ -63,12 +62,12 @@ Feature: channel spec When I run `rspec spec/channels/chat_channel_spec.rb` Then the example should pass - Scenario: performing actions and checking transmissions + Scenario: Performing actions and checking transmissions Given a file named "spec/channels/chat_channel_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ChatChannel, :type => :channel do + RSpec.describe ChatChannel, type: :channel do it "successfully subscribes" do subscribe room_id: 42 @@ -80,7 +79,7 @@ Feature: channel spec When I run `rspec spec/channels/chat_channel_spec.rb` Then the example should pass - Scenario: successful connection with url params + Scenario: A successful connection with url params Given a file named "app/channels/application_cable/connection.rb" with: """ruby class ApplicationCable::Connection < ActionCable::Connection::Base @@ -96,7 +95,7 @@ Feature: channel spec """ruby require "rails_helper" - RSpec.describe ApplicationCable::Connection, :type => :channel do + RSpec.describe ApplicationCable::Connection, type: :channel do it "successfully connects" do connect "/cable?user_id=323" expect(connection.user_id).to eq "323" @@ -106,7 +105,7 @@ Feature: channel spec When I run `rspec spec/channels/connection_spec.rb` Then the example should pass - Scenario: successful connection with cookies + Scenario: A successful connection with cookies Given a file named "app/channels/application_cable/connection.rb" with: """ruby class ApplicationCable::Connection < ActionCable::Connection::Base @@ -122,7 +121,7 @@ Feature: channel spec """ruby require "rails_helper" - RSpec.describe ApplicationCable::Connection, :type => :channel do + RSpec.describe ApplicationCable::Connection, type: :channel do it "successfully connects" do cookies.signed[:user_id] = "324" @@ -134,7 +133,7 @@ Feature: channel spec When I run `rspec spec/channels/connection_spec.rb` Then the example should pass - Scenario: successful connection with headers + Scenario: A successful connection with headers Given a file named "app/channels/application_cable/connection.rb" with: """ruby class ApplicationCable::Connection < ActionCable::Connection::Base @@ -150,7 +149,7 @@ Feature: channel spec """ruby require "rails_helper" - RSpec.describe ApplicationCable::Connection, :type => :channel do + RSpec.describe ApplicationCable::Connection, type: :channel do it "successfully connects" do connect "/cable", headers: { "X-USER-ID" => "325" } expect(connection.user_id).to eq "325" @@ -160,7 +159,7 @@ Feature: channel spec When I run `rspec spec/channels/connection_spec.rb` Then the example should pass - Scenario: rejected connection + Scenario: A rejected connection Given a file named "app/channels/application_cable/connection.rb" with: """ruby class ApplicationCable::Connection < ActionCable::Connection::Base @@ -176,7 +175,7 @@ Feature: channel spec """ruby require "rails_helper" - RSpec.describe ApplicationCable::Connection, :type => :channel do + RSpec.describe ApplicationCable::Connection, type: :channel do it "rejects connection" do expect { connect "/cable?user_id=" }.to have_rejected_connection end @@ -185,7 +184,7 @@ Feature: channel spec When I run `rspec spec/channels/connection_spec.rb` Then the example should pass - Scenario: disconnect connection + Scenario: Disconnect a connection Given a file named "app/channels/application_cable/connection.rb" with: """ruby class ApplicationCable::Connection < ActionCable::Connection::Base @@ -205,7 +204,7 @@ Feature: channel spec """ruby require "rails_helper" - RSpec.describe ApplicationCable::Connection, :type => :channel do + RSpec.describe ApplicationCable::Connection, type: :channel do it "disconnects" do connect "/cable?user_id=42" expect { disconnect }.to output(/User 42 disconnected/).to_stdout diff --git a/features/controller_specs/README.md b/features/controller_specs/README.md index c1e23f6aaf..39ba99c542 100644 --- a/features/controller_specs/README.md +++ b/features/controller_specs/README.md @@ -1,4 +1,6 @@ -Controller specs are marked by `:type => :controller` or if you have set +# Controller specs + +Controller specs are marked by `type: :controller` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/controllers`. A controller spec is an RSpec wrapper for a Rails functional test @@ -17,22 +19,22 @@ To specify outcomes, you can use: - standard test/unit assertions (`assert_equal 200, response.status`) - rails assertions (`assert_response 200`) - rails-specific matchers: - - [`render_template`](matchers/render-template-matcher) + - [`render_template`](./matchers/render-template-matcher) ```ruby expect(response).to render_template(:new) # wraps assert_template ``` - - [`redirect_to`](matchers/redirect-to-matcher) + - [`redirect_to`](./matchers/redirect-to-matcher) ```ruby expect(response).to redirect_to(location) # wraps assert_redirected_to ``` - - [`have_http_status`](matchers/have-http-status-matcher) + - [`have_http_status`](./matchers/have-http-status-matcher) ```ruby expect(response).to have_http_status(:created) ``` - - [`be_a_new`](matchers/be-a-new-matcher) + - [`be_a_new`](./matchers/new-record-matcher) ```ruby expect(assigns(:widget)).to be_a_new(Widget) @@ -58,12 +60,12 @@ To specify outcomes, you can use: ## Views * by default, views are not rendered. See - [views are stubbed by default](controller-specs/views-are-stubbed-by-default) and - [render_views](controller-specs/render-views) for details. + [views are stubbed by default](./controller-specs/isolation-from-views) and + [render_views](./controller-specs/render-views) for details. ## Headers -We encourage you to use [request specs](https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec) if you want to set headers in your call. If you still want to use controller specs with custom http headers you can use `request.headers`: +We encourage you to use [request specs](./request-specs/request-spec) if you want to set headers in your call. If you still want to use controller specs with custom http headers you can use `request.headers`: require "rails_helper" diff --git a/features/controller_specs/anonymous_controller.feature b/features/controller_specs/anonymous_controller.feature index 9baf73fb8d..b54b4d54d2 100644 --- a/features/controller_specs/anonymous_controller.feature +++ b/features/controller_specs/anonymous_controller.feature @@ -1,4 +1,4 @@ -Feature: anonymous controller +Feature: Using an anonymous controller Use the `controller` method to define an anonymous controller that will inherit from the described class. This is useful for specifying behavior like @@ -20,7 +20,7 @@ Feature: anonymous controller c.infer_base_class_for_anonymous_controllers = false end - RSpec.describe BaseController, :type => :controller do + RSpec.describe BaseController, type: :controller do controller do def index; end @@ -48,7 +48,7 @@ Feature: anonymous controller end end - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index raise ApplicationController::AccessDenied @@ -83,44 +83,7 @@ Feature: anonymous controller end end - RSpec.describe ApplicationController, :type => :controller do - controller do - def index - raise ApplicationController::AccessDenied - end - end - - describe "handling AccessDenied exceptions" do - it "renders the errors/401 template" do - get :index - expect(response).to render_template("errors/401") - end - end - end - """ - When I run `rspec spec` - Then the examples should all pass - - # Deprecated support removed in https://github.com/rails/rails/commit/d52d7739468153bd6cb7c629f60bd5cd7ebea3eb - @rails_pre_6 - Scenario: Specify error handling in `ApplicationController` with render :file - Given a file named "spec/controllers/application_controller_spec.rb" with: - """ruby - require "rails_helper" - - class ApplicationController < ActionController::Base - class AccessDenied < StandardError; end - - rescue_from AccessDenied, :with => :access_denied - - private - - def access_denied - render :file => "errors/401" - end - end - - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index raise ApplicationController::AccessDenied @@ -159,7 +122,7 @@ Feature: anonymous controller end end - RSpec.describe FoosController, :type => :controller do + RSpec.describe FoosController, type: :controller do controller(FoosController) do def index raise ApplicationController::AccessDenied @@ -186,7 +149,7 @@ Feature: anonymous controller class FoosController < ApplicationController; end - RSpec.describe FoosController, :type => :controller do + RSpec.describe FoosController, type: :controller do controller do def index render :plain => "Hello World" @@ -209,7 +172,7 @@ Feature: anonymous controller class ApplicationController < ActionController::Base; end class FoosController < ApplicationController; end - RSpec.describe "Access controller names", :type => :controller do + RSpec.describe "Access controller names", type: :controller do controller FoosController do def index @name = self.class.name @@ -248,7 +211,7 @@ Feature: anonymous controller end end - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index render :plain => "" @@ -276,7 +239,7 @@ Feature: anonymous controller ExpectedRoutingError = ActionController::RoutingError end - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index render :plain => "index called" @@ -454,7 +417,7 @@ Feature: anonymous controller """ruby require "rails_helper" - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def custom render :plain => "custom called" @@ -479,7 +442,7 @@ Feature: anonymous controller class OtherController < ActionController::Base end - RSpec.describe OtherController, :type => :controller do + RSpec.describe OtherController, type: :controller do controller do def custom render :plain => "custom called" @@ -504,7 +467,7 @@ Feature: anonymous controller class FoosController < ApplicationController; end - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller FoosController do def custom render :plain => "custom called" @@ -535,7 +498,7 @@ Feature: anonymous controller end end - RSpec.describe Outer::Inner::FoosController, :type => :controller do + RSpec.describe Outer::Inner::FoosController, type: :controller do controller do def index @name = self.class.name @@ -572,7 +535,7 @@ Feature: anonymous controller match "/login" => "sessions#new", :as => "login", :via => "get" end - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index redirect_to login_url diff --git a/features/controller_specs/bypass_rescue.feature b/features/controller_specs/bypass_rescue.feature index 438b68a50d..f89f36dc85 100644 --- a/features/controller_specs/bypass_rescue.feature +++ b/features/controller_specs/bypass_rescue.feature @@ -1,4 +1,4 @@ -Feature: bypass rescue +Feature: Using `bypass_rescue` Use `bypass_rescue` to bypass both Rails' default handling of errors in controller actions, and any custom handling declared with a `rescue_from` @@ -23,14 +23,14 @@ Feature: bypass rescue end """ - Scenario: standard exception handling using `rescue_from` + Scenario: Standard exception handling using `rescue_from` Given a file named "spec/controllers/gadgets_controller_spec.rb" with: """ruby require "rails_helper" require 'controllers/gadgets_controller_spec_context' - RSpec.describe GadgetsController, :type => :controller do + RSpec.describe GadgetsController, type: :controller do before do def controller.index raise AccessDenied @@ -48,14 +48,14 @@ Feature: bypass rescue When I run `rspec spec/controllers/gadgets_controller_spec.rb` Then the examples should all pass - Scenario: bypass `rescue_from` handling with `bypass_rescue` + Scenario: Bypass `rescue_from` handling with `bypass_rescue` Given a file named "spec/controllers/gadgets_controller_spec.rb" with: """ruby require "rails_helper" require 'controllers/gadgets_controller_spec_context' - RSpec.describe GadgetsController, :type => :controller do + RSpec.describe GadgetsController, type: :controller do before do def controller.index raise AccessDenied @@ -72,4 +72,3 @@ Feature: bypass rescue """ When I run `rspec spec/controllers/gadgets_controller_spec.rb` Then the examples should all pass - diff --git a/features/controller_specs/controller_spec.feature b/features/controller_specs/controller_spec.feature index 6ce5706beb..4b05afb5f3 100644 --- a/features/controller_specs/controller_spec.feature +++ b/features/controller_specs/controller_spec.feature @@ -1,11 +1,11 @@ -Feature: controller spec +Feature: Controller specs - Scenario: simple passing example + Scenario: A simple passing example Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "GET index" do it "has a 200 status code" do get :index @@ -17,14 +17,14 @@ Feature: controller spec When I run `rspec spec` Then the example should pass - Scenario: controller is exposed to global before hooks + Scenario: A controller is exposed to global before hooks Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" RSpec.configure {|c| c.before { expect(controller).not_to be_nil }} - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "GET index" do it "doesn't matter" do end @@ -34,36 +34,12 @@ Feature: controller spec When I run `rspec spec` Then the example should pass - @rails_pre_6 - Scenario: setting a different content type for example json (request type) - Given a file named "spec/controllers/widgets_controller_spec.rb" with: - """ruby - require "rails_helper" - - RSpec.describe WidgetsController, :type => :controller do - describe "responds to" do - it "responds to html by default" do - post :create, :params => { :widget => { :name => "Any Name" } } - expect(response.content_type).to eq "text/html" - end - - it "responds to custom formats when provided in the params" do - post :create, :params => { :widget => { :name => "Any Name" }, :format => :json } - expect(response.content_type).to eq "application/json" - end - end - end - """ - When I run `rspec spec` - Then the example should pass - - @rails_post_6 - Scenario: setting a different content type for example json (request type) + Scenario: Setting a different content type for example json (request type) Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "responds to" do it "responds to html by default" do post :create, :params => { :widget => { :name => "Any Name" } } @@ -80,13 +56,12 @@ Feature: controller spec When I run `rspec spec` Then the example should pass - @rails_post_6 - Scenario: setting a different media type for example json (request type) + Scenario: Setting a different media type for example json (request type) Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "responds to" do it "responds to html by default" do post :create, :params => { :widget => { :name => "Any Name" } } diff --git a/features/controller_specs/cookies.feature b/features/controller_specs/cookies.feature index a242e6cd2d..340951e4ca 100644 --- a/features/controller_specs/cookies.feature +++ b/features/controller_specs/cookies.feature @@ -11,7 +11,7 @@ Feature: Cookies """ruby require "rails_helper" - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def clear_cookie cookies.delete(:user_name) diff --git a/features/controller_specs/engine_routes.feature b/features/controller_specs/engine_routes.feature index 6493c6008f..3a088ff3e5 100644 --- a/features/controller_specs/engine_routes.feature +++ b/features/controller_specs/engine_routes.feature @@ -1,9 +1,9 @@ -Feature: engine routes for controllers +Feature: Engine routes for controllers Controller specs can specify the routeset that will be used for the example group. This is most useful when testing Rails engines. - Scenario: specify engine route + Scenario: Specify engine routes Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" @@ -33,7 +33,7 @@ Feature: engine routes for controllers end end - RSpec.describe MyEngine::WidgetsController, :type => :controller do + RSpec.describe MyEngine::WidgetsController, type: :controller do routes { MyEngine::Engine.routes } it "redirects to a random widget" do diff --git a/features/controller_specs/isolation_from_views.feature b/features/controller_specs/isolation_from_views.feature index 2a5971d832..a3fde66152 100644 --- a/features/controller_specs/isolation_from_views.feature +++ b/features/controller_specs/isolation_from_views.feature @@ -1,4 +1,4 @@ -Feature: views are stubbed by default +Feature: Views are stubbed by default By default, controller specs stub views with a template that renders an empty string instead of the views in the app. This allows you specify which view @@ -7,12 +7,12 @@ Feature: views are stubbed by default NOTE: unlike rspec-rails-1.x, the real template must exist. - Scenario: expect template that is rendered by controller action (passes) + Scenario: Expect a template that is rendered by controller action (passes) Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "index" do it "renders the index template" do get :index @@ -30,12 +30,12 @@ Feature: views are stubbed by default When I run `rspec spec` Then the examples should all pass - Scenario: expect template that is not rendered by controller action (fails) + Scenario: Expect a template that is not rendered by controller action (fails) Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "index" do it "renders the 'new' template" do get :index @@ -47,12 +47,12 @@ Feature: views are stubbed by default When I run `rspec spec` Then the output should contain "1 example, 1 failure" - Scenario: expect empty templates to render when view path is changed at runtime (passes) + Scenario: Expect empty templates to render when view path is changed at runtime (passes) Given a file named "spec/controllers/things_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ThingsController, :type => :controller do + RSpec.describe ThingsController, type: :controller do describe "custom_action" do it "renders an empty custom_action template" do controller.prepend_view_path 'app/views' @@ -78,12 +78,12 @@ Feature: views are stubbed by default When I run `rspec spec` Then the examples should all pass - Scenario: expect template to render the real template with render_views when view path is changed at runtime + Scenario: Expect a template to render the real template with render_views when view path is changed at runtime Given a file named "spec/controllers/things_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ThingsController, :type => :controller do + RSpec.describe ThingsController, type: :controller do render_views it "renders the real custom_action template" do diff --git a/features/controller_specs/render_views.feature b/features/controller_specs/render_views.feature index 7b7de72880..a77fa14d70 100644 --- a/features/controller_specs/render_views.feature +++ b/features/controller_specs/render_views.feature @@ -1,14 +1,14 @@ -Feature: render_views +Feature: Using `render_views` You can tell a controller example group to render views with the `render_views` declaration in any individual group, or globally. - Scenario: render_views directly in a single group + Scenario: Use `render_views` directly in a single group Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do render_views describe "GET index" do @@ -22,12 +22,12 @@ Feature: render_views When I run `rspec spec` Then the examples should all pass - Scenario: render_views on and off in nested groups + Scenario: Use `render_views` on and off in nested groups Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do context "with render_views" do render_views @@ -71,7 +71,7 @@ Feature: render_views end end """ - When I run `rspec spec --order default --format documentation` + When I run `rspec spec --order defined --format documentation` Then the output should contain: """ruby WidgetsController @@ -89,7 +89,7 @@ Feature: render_views renders the actual template """ - Scenario: render_views globally + Scenario: Use `render_views` globally Given a file named "spec/support/render_views.rb" with: """ruby RSpec.configure do |config| @@ -101,7 +101,7 @@ Feature: render_views require "rails_helper" require "support/render_views" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do describe "GET index" do it "renders the index template" do get :index diff --git a/features/controller_specs/setting_request_headers.feature b/features/controller_specs/setting_request_headers.feature index ff51943d5b..14b29e2f76 100644 --- a/features/controller_specs/setting_request_headers.feature +++ b/features/controller_specs/setting_request_headers.feature @@ -2,7 +2,7 @@ Feature: Setting request headers We recommend you to switch to request specs instead of controller specs if you want to set headers in your call. If you still want to set headers in controller specs, you can use - `request.headers` as mentioned bellow. + `request.headers` as mentioned below. Scenario: Setting a header value in a controller spec Given a file named "spec/controllers/application_controller_spec.rb" with: diff --git a/features/directory_structure.feature b/features/directory_structure.feature index d2bab53d4d..62150cf67a 100644 --- a/features/directory_structure.feature +++ b/features/directory_structure.feature @@ -1,27 +1,27 @@ -Feature: Directory Structure +Feature: The directory structure Specs are usually placed in a canonical directory structure that describes their purpose: - - [Model specs](model-specs) reside in the `spec/models` directory + - [Model specs](./model-specs) reside in the `spec/models` directory - - [Controller specs](controller-specs) reside in the `spec/controllers` directory + - [Controller specs](./controller-specs) reside in the `spec/controllers` directory - - [Request specs](request-specs) reside in the `spec/requests` directory. The directory can also be named `integration` or `api`. + - [Request specs](./request-specs) reside in the `spec/requests` directory. The directory can also be named `integration` or `api`. - - [Feature specs](feature-specs) reside in the `spec/features` directory + - [Feature specs](./feature-specs) reside in the `spec/features` directory - - [View specs](view-specs) reside in the `spec/views` directory + - [View specs](./view-specs) reside in the `spec/views` directory - - [Helper specs](helper-specs) reside in the `spec/helpers` directory + - [Helper specs](./helper-specs) reside in the `spec/helpers` directory - - [Mailer specs](mailer-specs) reside in the `spec/mailers` directory + - [Mailer specs](./mailer-specs) reside in the `spec/mailers` directory - - [Routing specs](routing-specs) reside in the `spec/routing` directory + - [Routing specs](./routing-specs) reside in the `spec/routing` directory - - [Job specs](job-specs) reside in the `spec/jobs` directory + - [Job specs](./job-specs) reside in the `spec/jobs` directory - - [System specs](system-specs) reside in the `spec/system` directory + - [System specs](./system-specs) reside in the `spec/system` directory Application developers are free to use a different directory structure. In order to include the correct `rspec-rails` support functions, the specs need @@ -54,10 +54,9 @@ Feature: Directory Structure **Note:** Standard RSpec specs do not require any additional metadata by default. - Check out the [`rspec-core`](/rspec/rspec-core/docs) documentation on [using metadata](/rspec/rspec-core/docs/metadata) for more details. + Check out the [`rspec-core`](../../3-12/rspec-core) documentation on [using metadata](../../3-12/rspec-core/metadata) for more details. - Automatically Adding Metadata - ----------------------------- + **Automatically Adding Metadata** RSpec versions before 3.0.0 automatically added metadata to specs based on their location on the filesystem. This was both confusing to new users and not @@ -90,8 +89,7 @@ Feature: Directory Structure end ``` - Tips on Spec Location - --------------------- + **Tips on Spec Location** It is suggested that the `spec/` directory structure generally mirror both `app/` and `lib/`. This makes it easy to locate corresponding code and spec @@ -145,7 +143,7 @@ Feature: Directory Structure """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do it "responds successfully" do get :index expect(response.status).to eq(200) @@ -205,7 +203,7 @@ Feature: Directory Structure # Due to limitations in the Rails routing test framework, routes that # perform redirects must actually be tested via request specs - RSpec.describe "/example", :type => :request do + RSpec.describe "/example", type: :request do it "redirects to example.com" do get "/example" expect(response).to redirect_to("http://example.com") diff --git a/features/feature_specs/feature_spec.feature b/features/feature_specs/feature_spec.feature index 9e097b7ab9..7e203e00d0 100644 --- a/features/feature_specs/feature_spec.feature +++ b/features/feature_specs/feature_spec.feature @@ -1,10 +1,10 @@ -Feature: Feature spec +Feature: Feature specs Feature specs are high-level tests meant to exercise slices of functionality through an application. They should drive the application only via its external interface, usually web pages. - Feature specs are marked by `:type => :feature` or if you have set + Feature specs are marked by `type: :feature` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/features`. @@ -15,15 +15,15 @@ Feature: Feature spec The `feature` and `scenario` DSL correspond to `describe` and `it`, respectively. These methods are simply aliases that allow feature specs to read more as [customer](http://c2.com/cgi/wiki?CustomerTest) and [acceptance](http://c2.com/cgi/wiki?AcceptanceTest) tests. When capybara is required it sets - `:type => :feature` automatically for you. + `type: :feature` automatically for you. @capybara - Scenario: specify creating a Widget by driving the application with capybara + Scenario: Specify creating a Widget by driving the application with capybara Given a file named "spec/features/widget_management_spec.rb" with: """ruby require "rails_helper" - RSpec.feature "Widget management", :type => :feature do + RSpec.feature "Widget management", type: :feature do scenario "User creates a new widget" do visit "/widgets/new" diff --git a/features/file_fixture.feature b/features/file_fixture.feature index 989d89c00f..c6a765a530 100644 --- a/features/file_fixture.feature +++ b/features/file_fixture.feature @@ -1,4 +1,5 @@ -Feature: file fixture +Feature: Using `file_fixture` + Rails 5 adds simple access to sample files called file fixtures. File fixtures are normal files stored in spec/fixtures/files by default. @@ -35,3 +36,22 @@ Feature: file fixture """ When I run `rspec spec/lib/file_spec.rb` Then the examples should all pass + + @rails_post_7 + Scenario: Creating a ActiveStorage::Blob from a file fixture + Given a file named "spec/fixtures/files/sample.txt" with: + """ + Hello + """ + And a file named "spec/lib/fixture_set_blob.rb" with: + """ruby + require "rails_helper" + + RSpec.describe "blob" do + it "creates a blob from a sample file" do + expect(ActiveStorage::FixtureSet.blob(filename: "sample.txt")).to include("sample.txt") + end + end + """ + When I run `rspec spec/lib/fixture_set_blob.rb` + Then the examples should all pass diff --git a/features/generator_specs/channel_specs.feature b/features/generator_specs/channel_specs.feature new file mode 100644 index 0000000000..67c1b5ae57 --- /dev/null +++ b/features/generator_specs/channel_specs.feature @@ -0,0 +1,31 @@ +Feature: Channel generator spec + + Scenario: Channel generator + When I run `bundle exec rails generate channel group` + Then the features should pass + Then the output should contain: + """ + invoke rspec + create spec/channels/group_channel_spec.rb + """ + Then the output should contain: + """ + create app/channels/group_channel.rb + """ + + Scenario: Channel generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate channel group` + Then the features should pass + Then the output should contain: + """ + invoke rspec + create behaviour/channels/group_channel_spec.rb + """ + Then the output should contain: + """ + create app/channels/group_channel.rb + """ diff --git a/features/generator_specs/controller_specs.feature b/features/generator_specs/controller_specs.feature new file mode 100644 index 0000000000..1973d467a6 --- /dev/null +++ b/features/generator_specs/controller_specs.feature @@ -0,0 +1,37 @@ +Feature: Controller generator spec + + Scenario: Controller generator + When I run `bundle exec rails generate controller posts` + Then the features should pass + Then the output should contain: + """ + create app/controllers/posts_controller.rb + invoke erb + create app/views/posts + invoke rspec + create spec/requests/posts_spec.rb + invoke helper + create app/helpers/posts_helper.rb + invoke rspec + create spec/helpers/posts_helper_spec.rb + """ + + Scenario: Controller generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate controller posts` + Then the features should pass + Then the output should contain: + """ + create app/controllers/posts_controller.rb + invoke erb + create app/views/posts + invoke rspec + create behaviour/requests/posts_spec.rb + invoke helper + create app/helpers/posts_helper.rb + invoke rspec + create behaviour/helpers/posts_helper_spec.rb + """ diff --git a/features/generator_specs/feature_specs.feature b/features/generator_specs/feature_specs.feature new file mode 100644 index 0000000000..867e78c6d9 --- /dev/null +++ b/features/generator_specs/feature_specs.feature @@ -0,0 +1,21 @@ +Feature: Feature generator spec + + Scenario: Feature generator + When I run `bundle exec rails generate rspec:feature posts` + Then the features should pass + Then the output should contain: + """ + create spec/features/posts_spec.rb + """ + + Scenario: Feature generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate rspec:feature posts` + Then the features should pass + Then the output should contain: + """ + create behaviour/features/posts_spec.rb + """ diff --git a/features/generator_specs/generator_specs.feature b/features/generator_specs/generator_specs.feature index 3a8e6d8360..2f9da13e5e 100644 --- a/features/generator_specs/generator_specs.feature +++ b/features/generator_specs/generator_specs.feature @@ -1,16 +1,33 @@ Feature: Generator spec - RSpec spec(s) can be generated when generating application components. For instance, `rails generate model` will also generate an RSpec spec file for the model but you can also write your own generator. See [customizing your workflow](https://guides.rubyonrails.org/generators.html#customizing-your-workflow) + RSpec spec(s) can be generated when generating application components. For instance, `rails generate model` will also generate an RSpec spec file for the model but you can also write your own generator. See [customizing your workflow](https://guides.rubyonrails.org/generators.html#customizing-your-workflow) - Scenario: Use custom generator - When I run `bundle exec rails generate generator my_generator` - Then the features should pass - Then the output should contain: - """ - create lib/generators/my_generator - create lib/generators/my_generator/my_generator_generator.rb - create lib/generators/my_generator/USAGE - create lib/generators/my_generator/templates - invoke rspec - create spec/generator/my_generators_generator_spec.rb - """ + Scenario: Use custom generator + When I run `bundle exec rails generate generator my_generator` + Then the features should pass + Then the output should contain: + """ + create lib/generators/my_generator + create lib/generators/my_generator/my_generator_generator.rb + create lib/generators/my_generator/USAGE + create lib/generators/my_generator/templates + invoke rspec + create spec/generator/my_generators_generator_spec.rb + """ + + Scenario: Use custom generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate generator my_generator` + Then the features should pass + Then the output should contain: + """ + create lib/generators/my_generator + create lib/generators/my_generator/my_generator_generator.rb + create lib/generators/my_generator/USAGE + create lib/generators/my_generator/templates + invoke rspec + create behaviour/generator/my_generators_generator_spec.rb + """ diff --git a/features/generator_specs/helper_specs.feature b/features/generator_specs/helper_specs.feature new file mode 100644 index 0000000000..a4ffeed0cc --- /dev/null +++ b/features/generator_specs/helper_specs.feature @@ -0,0 +1,25 @@ +Feature: Helper generator spec + + Scenario: Helper generator + When I run `bundle exec rails generate helper posts` + Then the features should pass + Then the output should contain: + """ + create app/helpers/posts_helper.rb + invoke rspec + create spec/helpers/posts_helper_spec.rb + """ + + Scenario: Helper generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate helper posts` + Then the features should pass + Then the output should contain: + """ + create app/helpers/posts_helper.rb + invoke rspec + create behaviour/helpers/posts_helper_spec.rb + """ diff --git a/features/generator_specs/integration_specs.feature b/features/generator_specs/integration_specs.feature new file mode 100644 index 0000000000..ea9c142423 --- /dev/null +++ b/features/generator_specs/integration_specs.feature @@ -0,0 +1,21 @@ +Feature: Integration generator spec + + Scenario: Integration generator + When I run `bundle exec rails generate rspec:integration posts` + Then the features should pass + Then the output should contain: + """ + create spec/requests/posts_spec.rb + """ + + Scenario: Integration generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate rspec:integration posts` + Then the features should pass + Then the output should contain: + """ + create behaviour/requests/posts_spec.rb + """ diff --git a/features/generator_specs/job_specs.feature b/features/generator_specs/job_specs.feature new file mode 100644 index 0000000000..277a89c229 --- /dev/null +++ b/features/generator_specs/job_specs.feature @@ -0,0 +1,25 @@ +Feature: Job generator spec + + Scenario: Job generator + When I run `bundle exec rails generate job user` + Then the features should pass + Then the output should contain: + """ + invoke rspec + create spec/jobs/user_job_spec.rb + create app/jobs/user_job.rb + """ + + Scenario: Job generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate job user` + Then the features should pass + Then the output should contain: + """ + invoke rspec + create behaviour/jobs/user_job_spec.rb + create app/jobs/user_job.rb + """ diff --git a/features/generator_specs/mailbox_specs.feature b/features/generator_specs/mailbox_specs.feature new file mode 100644 index 0000000000..ffdb9fa19e --- /dev/null +++ b/features/generator_specs/mailbox_specs.feature @@ -0,0 +1,25 @@ +Feature: Mailbox generator spec + + Scenario: Mailbox generator + When I run `bundle exec rails generate mailbox forwards` + Then the features should pass + Then the output should contain: + """ + create app/mailboxes/forwards_mailbox.rb + invoke rspec + create spec/mailboxes/forwards_mailbox_spec.rb + """ + + Scenario: Mailbox generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate mailbox forwards` + Then the features should pass + Then the output should contain: + """ + create app/mailboxes/forwards_mailbox.rb + invoke rspec + create behaviour/mailboxes/forwards_mailbox_spec.rb + """ diff --git a/features/generator_specs/mailer_specs.feature b/features/generator_specs/mailer_specs.feature new file mode 100644 index 0000000000..26f171969c --- /dev/null +++ b/features/generator_specs/mailer_specs.feature @@ -0,0 +1,43 @@ +Feature: Mailer generator spec + + Scenario: Mailer generator + When I run `bundle exec rails generate mailer posts index show` + Then the features should pass + Then the output should contain: + """ + create app/mailers/posts_mailer.rb + invoke erb + create app/views/posts_mailer + create app/views/posts_mailer/index.text.erb + create app/views/posts_mailer/index.html.erb + create app/views/posts_mailer/show.text.erb + create app/views/posts_mailer/show.html.erb + invoke rspec + create spec/mailers/posts_spec.rb + create spec/fixtures/posts/index + create spec/fixtures/posts/show + create spec/mailers/previews/posts_preview.rb + """ + + Scenario: Mailer generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate mailer posts index show` + Then the features should pass + Then the output should contain: + """ + create app/mailers/posts_mailer.rb + invoke erb + create app/views/posts_mailer + create app/views/posts_mailer/index.text.erb + create app/views/posts_mailer/index.html.erb + create app/views/posts_mailer/show.text.erb + create app/views/posts_mailer/show.html.erb + invoke rspec + create behaviour/mailers/posts_spec.rb + create behaviour/fixtures/posts/index + create behaviour/fixtures/posts/show + create behaviour/mailers/previews/posts_preview.rb + """ diff --git a/features/generator_specs/request_specs.feature b/features/generator_specs/request_specs.feature new file mode 100644 index 0000000000..a4ccc5f031 --- /dev/null +++ b/features/generator_specs/request_specs.feature @@ -0,0 +1,21 @@ +Feature: Request generator spec + + Scenario: Request generator + When I run `bundle exec rails generate rspec:request posts` + Then the features should pass + Then the output should contain: + """ + create spec/requests/posts_spec.rb + """ + + Scenario: Request generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate rspec:request posts` + Then the features should pass + Then the output should contain: + """ + create behaviour/requests/posts_spec.rb + """ diff --git a/features/generator_specs/system_specs.feature b/features/generator_specs/system_specs.feature new file mode 100644 index 0000000000..24afec0a81 --- /dev/null +++ b/features/generator_specs/system_specs.feature @@ -0,0 +1,21 @@ +Feature: System generator spec + + Scenario: System generator + When I run `bundle exec rails generate rspec:system posts` + Then the features should pass + Then the output should contain: + """ + create spec/system/posts_spec.rb + """ + + Scenario: System generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate rspec:system posts` + Then the features should pass + Then the output should contain: + """ + create behaviour/system/posts_spec.rb + """ diff --git a/features/generator_specs/view_specs.feature b/features/generator_specs/view_specs.feature new file mode 100644 index 0000000000..2e684b11a5 --- /dev/null +++ b/features/generator_specs/view_specs.feature @@ -0,0 +1,23 @@ +Feature: View generator spec + + Scenario: View generator + When I run `bundle exec rails generate rspec:view posts index` + Then the features should pass + Then the output should contain: + """ + create spec/views/posts + create spec/views/posts/index.html.erb_spec.rb + """ + + Scenario: View generator with customized `default-path` + Given a file named ".rspec" with: + """ + --default-path behaviour + """ + And I run `bundle exec rails generate rspec:view posts index` + Then the features should pass + Then the output should contain: + """ + create behaviour/views/posts + create behaviour/views/posts/index.html.erb_spec.rb + """ diff --git a/features/helper_specs/helper_spec.feature b/features/helper_specs/helper_spec.feature index 94a7f34b6d..5a5aee7a20 100644 --- a/features/helper_specs/helper_spec.feature +++ b/features/helper_specs/helper_spec.feature @@ -1,6 +1,6 @@ -Feature: helper spec +Feature: Helper specs - Helper specs are marked by `:type => :helper` or if you have set + Helper specs are marked by `type: :helper` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/helpers`. Helper specs expose a `helper` object, which includes the helper module being @@ -13,12 +13,12 @@ Feature: helper spec NOTE: helper methods defined in controllers are not included. - Scenario: helper method that returns a value + Scenario: A helper method that returns a value Given a file named "spec/helpers/application_helper_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ApplicationHelper, :type => :helper do + RSpec.describe ApplicationHelper, type: :helper do describe "#page_title" do it "returns the default title" do expect(helper.page_title).to eq("RSpec is your friend") @@ -37,12 +37,12 @@ Feature: helper spec When I run `rspec spec/helpers/application_helper_spec.rb` Then the examples should all pass - Scenario: helper method that accesses an instance variable + Scenario: A helper method that accesses an instance variable Given a file named "spec/helpers/application_helper_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ApplicationHelper, :type => :helper do + RSpec.describe ApplicationHelper, type: :helper do describe "#page_title" do it "returns the instance variable" do assign(:title, "My Title") @@ -62,12 +62,12 @@ Feature: helper spec When I run `rspec spec/helpers/application_helper_spec.rb` Then the examples should all pass - Scenario: application helper is included in helper object + Scenario: Application helper is included in helper object Given a file named "spec/helpers/widgets_helper_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsHelper, :type => :helper do + RSpec.describe WidgetsHelper, type: :helper do describe "#widget_title" do it "includes the app name" do assign(:title, "This Widget") @@ -95,12 +95,12 @@ Feature: helper spec When I run `rspec spec/helpers/widgets_helper_spec.rb` Then the examples should all pass - Scenario: url helpers are defined + Scenario: Url helpers are defined Given a file named "spec/helpers/widgets_helper_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsHelper, :type => :helper do + RSpec.describe WidgetsHelper, type: :helper do describe "#link_to_widget" do it "links to a widget using its name" do widget = Widget.create!(:name => "This Widget") diff --git a/features/job_specs/job_spec.feature b/features/job_specs/job_spec.feature index 1b8613ba0f..bae8881e6d 100644 --- a/features/job_specs/job_spec.feature +++ b/features/job_specs/job_spec.feature @@ -1,8 +1,8 @@ -Feature: job spec +Feature: Job specs Job specs provide alternative assertions to those available in `ActiveJob::TestHelper` and help assert behaviour of the jobs themselves and that other entities correctly enqueue them. - Job specs are marked by `:type => :job` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/jobs`. + Job specs are marked by `type: :job` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/jobs`. With job specs, you can: @@ -21,12 +21,12 @@ Feature: job spec Background: Given active job is available - Scenario: specify that job was enqueued - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: Specify that job was enqueued + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :test @@ -37,15 +37,15 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should pass - Scenario: specify that job was enqueued for the correct date and time - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: Specify that job was enqueued for the correct date and time + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :test @@ -56,15 +56,15 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should pass - Scenario: specify that job was enqueued with no wait - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: Specify that job was enqueued with no wait + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :test @@ -75,15 +75,15 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should pass - Scenario: specify that job was enqueued with alias block syntax - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: Specify that job was enqueued with alias block syntax + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :test @@ -94,15 +94,15 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should pass - Scenario: specify that job was enqueued with imperative syntax - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: Specify that job was enqueued with imperative syntax + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :test @@ -112,15 +112,15 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should pass - Scenario: specify that job was enqueued with imperative syntax and a chained expectation - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: Specify that job was enqueued with imperative syntax and a chained expectation + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :test @@ -130,15 +130,15 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should pass - Scenario: the test adapter must be set to :test - Given a file named "spec/jobs/upload_backups_spec.rb" with: + Scenario: The test adapter must be set to `:test` + Given a file named "spec/jobs/upload_backups_job_spec.rb" with: """ruby require "rails_helper" - RSpec.describe UploadBackupsJob, :type => :job do + RSpec.describe UploadBackupsJob, type: :job do describe "#perform_later" do it "uploads a backup" do ActiveJob::Base.queue_adapter = :development @@ -146,5 +146,5 @@ Feature: job spec end end """ - When I run `rspec spec/jobs/upload_backups_spec.rb` + When I run `rspec spec/jobs/upload_backups_job_spec.rb` Then the example should fail diff --git a/features/mailbox_specs/mailbox_spec.feature b/features/mailbox_specs/mailbox_spec.feature index e1a9a62345..02b0cf5526 100644 --- a/features/mailbox_specs/mailbox_spec.feature +++ b/features/mailbox_specs/mailbox_spec.feature @@ -1,5 +1,4 @@ -@rails_post_6 -Feature: action mailbox spec +Feature: Action mailbox specs Mailbox specs provide alternative assertions to those available in `ActiveMailbox::TestHelper` and help assert behaviour of how the email are routed, delivered, bounced or failed. diff --git a/features/mailer_specs/README.md b/features/mailer_specs/README.md index 054c149deb..555cc4851b 100644 --- a/features/mailer_specs/README.md +++ b/features/mailer_specs/README.md @@ -1,5 +1,7 @@ +# Mailer sepcs + By default Mailer specs reside in the `spec/mailers` folder. Adding the metadata -`:type => :mailer` to any context makes its examples be treated as mailer specs. +`type: :mailer` to any context makes its examples be treated as mailer specs. A mailer spec is a thin wrapper for an ActionMailer::TestCase, and includes all of the behavior and assertions that it provides, in addition to RSpec's own @@ -9,7 +11,7 @@ behavior and expectations. require "rails_helper" - RSpec.describe Notifications, :type => :mailer do + RSpec.describe Notifications, type: :mailer do describe "notify" do let(:mail) { Notifications.signup } diff --git a/features/mailer_specs/mailer_spec.feature b/features/mailer_specs/mailer_spec.feature index 7036193018..6c77da0f83 100644 --- a/features/mailer_specs/mailer_spec.feature +++ b/features/mailer_specs/mailer_spec.feature @@ -1,11 +1,11 @@ -Feature: mailer spec +Feature: Mailer specs - Scenario: simple passing example + Scenario: A simple passing example Given a file named "spec/mailers/notifications_mailer_spec.rb" with: """ruby require "rails_helper" - RSpec.describe NotificationsMailer, :type => :mailer do + RSpec.describe NotificationsMailer, type: :mailer do describe "notify" do let(:mail) { NotificationsMailer.signup } diff --git a/features/mailer_specs/url_helpers.feature b/features/mailer_specs/url_helpers.feature index 4e82101303..60cf63ce29 100644 --- a/features/mailer_specs/url_helpers.feature +++ b/features/mailer_specs/url_helpers.feature @@ -1,9 +1,9 @@ Feature: URL helpers in mailer examples - Mailer specs are marked by `:type => :mailer` or if you have set + Mailer specs are marked by `type: :mailer` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/mailers`. - Scenario: using URL helpers with default options + Scenario: Using URL helpers with default options Given a file named "config/initializers/mailer_defaults.rb" with: """ruby Rails.configuration.action_mailer.default_url_options = { :host => 'example.com' } @@ -12,7 +12,7 @@ Feature: URL helpers in mailer examples """ruby require 'rails_helper' - RSpec.describe NotificationsMailer, :type => :mailer do + RSpec.describe NotificationsMailer, type: :mailer do it 'should have access to URL helpers' do expect { gadgets_url }.not_to raise_error end @@ -21,7 +21,7 @@ Feature: URL helpers in mailer examples When I run `rspec spec` Then the examples should all pass - Scenario: using URL helpers without default options + Scenario: Using URL helpers without default options Given a file named "config/initializers/mailer_defaults.rb" with: """ruby # no default options @@ -30,7 +30,7 @@ Feature: URL helpers in mailer examples """ruby require 'rails_helper' - RSpec.describe NotificationsMailer, :type => :mailer do + RSpec.describe NotificationsMailer, type: :mailer do it 'should have access to URL helpers' do expect { gadgets_url :host => 'example.com' }.not_to raise_error expect { gadgets_url }.to raise_error diff --git a/features/matchers/README.md b/features/matchers/README.md index 76efa29316..78810444b4 100644 --- a/features/matchers/README.md +++ b/features/matchers/README.md @@ -1,3 +1,5 @@ +# Matchers + rspec-rails offers a number of custom matchers, most of which are rspec-compatible wrappers for Rails' assertions. diff --git a/features/matchers/have_been_enqueued_matcher.feature b/features/matchers/have_been_enqueued_matcher.feature index 86bfd81f07..41a7fe204e 100644 --- a/features/matchers/have_been_enqueued_matcher.feature +++ b/features/matchers/have_been_enqueued_matcher.feature @@ -1,4 +1,4 @@ -Feature: have_been_enqueued matcher +Feature: `have_been_enqueued` matcher The `have_been_enqueued` matcher is used to check if given ActiveJob job was enqueued. diff --git a/features/matchers/have_been_performed_matcher.feature b/features/matchers/have_been_performed_matcher.feature index 813e65e5da..95ba2a68f6 100644 --- a/features/matchers/have_been_performed_matcher.feature +++ b/features/matchers/have_been_performed_matcher.feature @@ -1,4 +1,4 @@ -Feature: have_been_performed matcher +Feature: `have_been_performed` matcher The `have_been_performed` matcher is used to check if given ActiveJob job was performed. diff --git a/features/matchers/have_broadcasted_matcher.feature b/features/matchers/have_broadcasted_matcher.feature index 1c0dc25777..3d60085eb8 100644 --- a/features/matchers/have_broadcasted_matcher.feature +++ b/features/matchers/have_broadcasted_matcher.feature @@ -1,5 +1,4 @@ -@rails_post_6 -Feature: have_broadcasted matcher +Feature: `have_broadcasted_to` matcher The `have_broadcasted_to` (also aliased as `broadcast_to`) matcher is used to check if a message has been broadcasted to a given stream. diff --git a/features/matchers/have_enqueued_job_matcher.feature b/features/matchers/have_enqueued_job_matcher.feature index 984132a797..d4217ced49 100644 --- a/features/matchers/have_enqueued_job_matcher.feature +++ b/features/matchers/have_enqueued_job_matcher.feature @@ -1,4 +1,4 @@ -Feature: have_enqueued_job matcher +Feature: `have_enqueued_job` matcher The `have_enqueued_job` (also aliased as `enqueue_job`) matcher is used to check if given ActiveJob job was enqueued. diff --git a/features/matchers/have_enqueued_mail_matcher.feature b/features/matchers/have_enqueued_mail_matcher.feature index dda6b46f9d..d6839aed5c 100644 --- a/features/matchers/have_enqueued_mail_matcher.feature +++ b/features/matchers/have_enqueued_mail_matcher.feature @@ -1,4 +1,4 @@ -Feature: have_enqueued_mail matcher +Feature: `have_enqueued_mail` matcher The `have_enqueued_mail` (also aliased as `enqueue_mail`) matcher is used to check if given mailer was enqueued. @@ -68,7 +68,6 @@ Feature: have_enqueued_mail matcher When I run `rspec spec/mailers/my_mailer_spec.rb` Then the examples should all pass - @rails_post_6 Scenario: Parameterize the mailer Given a file named "app/mailers/my_mailer.rb" with: """ruby @@ -98,7 +97,6 @@ Feature: have_enqueued_mail matcher When I run `rspec spec/mailers/my_mailer_spec.rb` Then the examples should all pass - @rails_post_6 Scenario: Parameterize and pass an argument to the mailer Given a file named "app/mailers/my_mailer.rb" with: """ruby diff --git a/features/matchers/have_http_status_matcher.feature b/features/matchers/have_http_status_matcher.feature index 27690ecda9..5ed3fb6c74 100644 --- a/features/matchers/have_http_status_matcher.feature +++ b/features/matchers/have_http_status_matcher.feature @@ -15,7 +15,7 @@ Feature: `have_http_status` matcher """ruby require "rails_helper" - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index @@ -40,7 +40,7 @@ Feature: `have_http_status` matcher """ruby require "rails_helper" - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index @@ -65,7 +65,7 @@ Feature: `have_http_status` matcher """ruby require "rails_helper" - RSpec.describe ApplicationController, :type => :controller do + RSpec.describe ApplicationController, type: :controller do controller do def index @@ -90,7 +90,7 @@ Feature: `have_http_status` matcher """ruby require "rails_helper" - RSpec.describe GadgetsController, :type => :controller do + RSpec.describe GadgetsController, type: :controller do describe "GET #index" do it "returns a 200 OK status" do @@ -109,7 +109,7 @@ Feature: `have_http_status` matcher """ruby require "rails_helper" - RSpec.describe "Widget management", :type => :request do + RSpec.describe "Widget management", type: :request do it "creates a Widget and redirects to the Widget's page" do get "/widgets/new" @@ -134,7 +134,7 @@ Feature: `have_http_status` matcher """ruby require "rails_helper" - RSpec.feature "Widget management", :type => :feature do + RSpec.feature "Widget management", type: :feature do scenario "User creates a new widget" do visit "/widgets/new" diff --git a/features/matchers/have_performed_job_matcher.feature b/features/matchers/have_performed_job_matcher.feature index cb442640d0..7538dcb5c7 100644 --- a/features/matchers/have_performed_job_matcher.feature +++ b/features/matchers/have_performed_job_matcher.feature @@ -1,4 +1,4 @@ -Feature: have_performed_job matcher +Feature: `have_performed_job` matcher The `have_performed_job` (also aliased as `perform_job`) matcher is used to check if given ActiveJob job was performed. diff --git a/features/matchers/have_stream_from_matcher.feature b/features/matchers/have_stream_from_matcher.feature index 9de55cfcf9..b16a14d378 100644 --- a/features/matchers/have_stream_from_matcher.feature +++ b/features/matchers/have_stream_from_matcher.feature @@ -1,10 +1,9 @@ -@rails_post_6 -Feature: have_stream_from matcher +Feature: `have_stream_from` matcher The `have_stream_from` matcher is used to check if a channel has been subscribed to a given stream specified as a String. If you use `stream_for` in you channel to subscribe to a model, use `have_stream_for` matcher instead. - The `have_no_streams` matcher is used to check if a channe hasn't been subscribed to any stream. + The `have_no_streams` matcher is used to check if a channel hasn't been subscribed to any stream. It is available only in channel specs. @@ -26,12 +25,12 @@ Feature: have_stream_from matcher end """ - Scenario: subscribing with params and checking streams + Scenario: Subscribing with params and checking streams Given a file named "spec/channels/chat_channel_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ChatChannel, :type => :channel do + RSpec.describe ChatChannel, type: :channel do it "successfully subscribes" do subscribe room_id: 42 @@ -43,12 +42,12 @@ Feature: have_stream_from matcher When I run `rspec spec/channels/chat_channel_spec.rb` Then the example should pass - Scenario: stopping all streams + Scenario: Stopping all streams Given a file named "spec/channels/chat_channel_spec.rb" with: """ruby require "rails_helper" - RSpec.describe ChatChannel, :type => :channel do + RSpec.describe ChatChannel, type: :channel do it "successfully subscribes" do subscribe(room_id: 42) @@ -62,7 +61,7 @@ Feature: have_stream_from matcher When I run `rspec spec/channels/chat_channel_spec.rb` Then the example should pass - Scenario: subscribing and checking streams for models + Scenario: Subscribing and checking streams for models Given a file named "app/channels/notifications_channel.rb" with: """ruby class NotificationsChannel < ApplicationCable::Channel @@ -88,7 +87,7 @@ Feature: have_stream_from matcher And a file named "spec/channels/user_channel_spec.rb" with: """ruby require "rails_helper" - RSpec.describe NotificationsChannel, :type => :channel do + RSpec.describe NotificationsChannel, type: :channel do it "successfully subscribes to user's stream" do stub_connection current_user: User.new(42) subscribe diff --git a/features/matchers/new_record_matcher.feature b/features/matchers/new_record_matcher.feature index 0d47e2c5c8..e96f626477 100644 --- a/features/matchers/new_record_matcher.feature +++ b/features/matchers/new_record_matcher.feature @@ -1,4 +1,4 @@ -Feature: be_a_new matcher +Feature: `be_a_new` matcher The `be_a_new` matcher accepts a class and passes if the subject is an instance of that class that returns false to persisted? @@ -6,7 +6,7 @@ Feature: be_a_new matcher You can also chain `with` on `be_a_new` with a hash of attributes to specify the subject has equal attributes. - Scenario: example spec with four be_a_new possibilities + Scenario: An example spec with four be_a_new possibilities Given a file named "spec/models/widget_spec.rb" with: """ruby require "rails_helper" diff --git a/features/matchers/redirect_to_matcher.feature b/features/matchers/redirect_to_matcher.feature index a4b634202e..5abfe3eef1 100644 --- a/features/matchers/redirect_to_matcher.feature +++ b/features/matchers/redirect_to_matcher.feature @@ -1,4 +1,4 @@ -Feature: redirect_to matcher +Feature: `redirect_to` matcher The `redirect_to` matcher is used to specify that a request redirects to a given template or action. It delegates to @@ -7,7 +7,7 @@ Feature: redirect_to matcher It is available in controller specs (spec/controllers) and request specs (spec/requests). - Scenario: redirect_to with four possible options + Scenario: Using `redirect_to` with four possible options Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" diff --git a/features/matchers/relation_match_array.feature b/features/matchers/relation_match_array.feature index 4fb6fdd4e7..1561e95bb5 100644 --- a/features/matchers/relation_match_array.feature +++ b/features/matchers/relation_match_array.feature @@ -4,7 +4,7 @@ Feature: ActiveRecord::Relation match array (scope). The assertion will pass if the scope would return all of the elements specified in the array on the right hand side. - Scenario: example spec with relation match_array matcher + Scenario: An example spec with relation match_array matcher Given a file named "spec/models/widget_spec.rb" with: """ruby require "rails_helper" diff --git a/features/matchers/render_template_matcher.feature b/features/matchers/render_template_matcher.feature index 527d598e64..e8f7f3f914 100644 --- a/features/matchers/render_template_matcher.feature +++ b/features/matchers/render_template_matcher.feature @@ -1,15 +1,15 @@ -Feature: render_template matcher +Feature: `render_template` matcher The `render_template` matcher is used to specify that a request renders a given template or layout. It delegates to - [`assert_template`](https://api.rubyonrails.org/classes/ActionController/TemplateAssertions.html#method-i-assert_template) + [`assert_template`](https://api.rubyonrails.org/v5.2/classes/ActionController/TemplateAssertions.html#method-i-assert_template) It is available in controller specs (spec/controllers) and request specs (spec/requests). NOTE: use `redirect_to(:action => 'new')` for redirects, not `render_template`. - Scenario: render_template with three possible options + Scenario: Using `render_template` with three possible options Given a file named "spec/controllers/gadgets_spec.rb" with: """ruby require "rails_helper" @@ -33,7 +33,7 @@ Feature: render_template matcher When I run `rspec spec/controllers/gadgets_spec.rb` Then the examples should all pass - Scenario: specify that a request renders a given layout + Scenario: Specify that a request renders a given layout Given a file named "spec/controllers/gadgets_spec.rb" with: """ruby require "rails_helper" @@ -55,7 +55,7 @@ Feature: render_template matcher When I run `rspec spec/controllers/gadgets_spec.rb` Then the examples should all pass - Scenario: render_template in a view spec + Scenario: Using `render_template` in a view spec Given a file named "spec/views/gadgets/index.html.erb_spec.rb" with: """ruby require "rails_helper" diff --git a/features/model_specs/README.md b/features/model_specs/README.md index 6842e59944..418a4a3037 100644 --- a/features/model_specs/README.md +++ b/features/model_specs/README.md @@ -1,4 +1,6 @@ -Model specs are marked by `:type => :model` or if you have set +# Model specs + +Model specs are marked by `type: :model` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/models`. A model spec is a thin wrapper for an ActiveSupport::TestCase, and includes all @@ -9,7 +11,7 @@ behavior and expectations. require "rails_helper" - RSpec.describe Post, :type => :model do + RSpec.describe Post, type: :model do context "with 2 or more comments" do it "orders them in reverse chronologically" do post = Post.create! diff --git a/features/model_specs/transactional_examples.feature b/features/model_specs/transactional_examples.feature index 00423cbf49..82cedad8fd 100644 --- a/features/model_specs/transactional_examples.feature +++ b/features/model_specs/transactional_examples.feature @@ -1,16 +1,16 @@ -Feature: transactional examples +Feature: Transactional examples By default rspec executes each individual example in a transaction. You can also explicitly enable/disable transactions the configuration property 'use_transactional_examples'. - Scenario: run in transactions (default) + Scenario: Run in transactions (default) Given a file named "spec/models/widget_spec.rb" with: """ruby require "rails_helper" - RSpec.describe Widget, :type => :model do + RSpec.describe Widget, type: :model do it "has none to begin with" do expect(Widget.count).to eq 0 end @@ -28,7 +28,7 @@ Feature: transactional examples When I run `rspec spec/models/widget_spec.rb` Then the examples should all pass - Scenario: run in transactions (explicit) + Scenario: Run in transactions (explicit) Given a file named "spec/models/widget_spec.rb" with: """ruby require "rails_helper" @@ -37,7 +37,7 @@ Feature: transactional examples c.use_transactional_examples = true end - RSpec.describe Widget, :type => :model do + RSpec.describe Widget, type: :model do it "has none to begin with" do expect(Widget.count).to eq 0 end @@ -55,7 +55,7 @@ Feature: transactional examples When I run `rspec spec/models/widget_spec.rb` Then the examples should all pass - Scenario: disable transactions (explicit) + Scenario: Disable transactions (explicit) Given a file named "spec/models/widget_spec.rb" with: """ruby require "rails_helper" @@ -65,7 +65,7 @@ Feature: transactional examples c.order = "defined" end - RSpec.describe Widget, :type => :model do + RSpec.describe Widget, type: :model do it "has none to begin with" do expect(Widget.count).to eq 0 end @@ -85,12 +85,12 @@ Feature: transactional examples When I run `rspec spec/models/widget_spec.rb` Then the examples should all pass - Scenario: run in transactions with fixture + Scenario: Run in transactions with fixture Given a file named "spec/models/thing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe Thing, :type => :model do + RSpec.describe Thing, type: :model do fixtures :things it "fixture method defined" do things(:one) @@ -104,6 +104,3 @@ Feature: transactional examples """ When I run `rspec spec/models/thing_spec.rb` Then the examples should all pass - - - diff --git a/features/model_specs/verified_doubles.feature b/features/model_specs/verified_doubles.feature index 7e0ee9b47c..0f47a7a0f6 100644 --- a/features/model_specs/verified_doubles.feature +++ b/features/model_specs/verified_doubles.feature @@ -1,4 +1,4 @@ -Feature: verified doubles +Feature: Using verified doubles By default rspec verified doubles dont support dynamic methods on `instance_double`. `rspec-rails` enabled this support for column @@ -9,7 +9,7 @@ Feature: verified doubles """ruby require "rails_helper" - RSpec.describe Widget, :type => :model do + RSpec.describe Widget, type: :model do it "has one after adding one" do instance_double("Widget", :name => "my name") end diff --git a/features/request_specs/request_spec.feature b/features/request_specs/request_spec.feature index aa312c8f12..1a27f7a5ab 100644 --- a/features/request_specs/request_spec.feature +++ b/features/request_specs/request_spec.feature @@ -1,10 +1,10 @@ -Feature: request spec +Feature: Request specs Request specs provide a thin wrapper around Rails' integration tests, and are designed to drive behavior through the full stack, including routing (provided by Rails) and without stubbing (that's up to you). - Request specs are marked by `:type => :request` or if you have set + Request specs are marked by `type: :request` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/requests`. With request specs, you can: @@ -26,12 +26,12 @@ Feature: request spec request specs. The recommended way to use Capybara is with [feature specs](../feature-specs/feature-spec). - Scenario: specify managing a Widget with Rails integration methods + Scenario: Specify managing a Widget with Rails integration methods Given a file named "spec/requests/widget_management_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "Widget management", :type => :request do + RSpec.describe "Widget management", type: :request do it "creates a Widget and redirects to the Widget's page" do get "/widgets/new" @@ -55,34 +55,12 @@ Feature: request spec When I run `rspec spec/requests/widget_management_spec.rb` Then the example should pass - @rails_pre_6 - Scenario: requesting a JSON response - Given a file named "spec/requests/widget_management_spec.rb" with: - """ruby - require "rails_helper" - - RSpec.describe "Widget management", :type => :request do - - it "creates a Widget" do - headers = { "ACCEPT" => "application/json" } - post "/widgets", :params => { :widget => {:name => "My Widget"} }, :headers => headers - - expect(response.content_type).to eq("application/json") - expect(response).to have_http_status(:created) - end - - end - """ - When I run `rspec spec/requests/widget_management_spec.rb` - Then the example should pass - - @rails_post_6 - Scenario: requesting a JSON response + Scenario: Requesting a JSON response Given a file named "spec/requests/widget_management_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "Widget management", :type => :request do + RSpec.describe "Widget management", type: :request do it "creates a Widget" do headers = { "ACCEPT" => "application/json" } post "/widgets", :params => { :widget => {:name => "My Widget"} }, :headers => headers @@ -95,12 +73,12 @@ Feature: request spec When I run `rspec spec/requests/widget_management_spec.rb` Then the example should pass - Scenario: providing JSON data + Scenario: Providing JSON data Given a file named "spec/requests/widget_management_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "Widget management", :type => :request do + RSpec.describe "Widget management", type: :request do it "creates a Widget and redirects to the Widget's page" do headers = { "CONTENT_TYPE" => "application/json" } @@ -113,7 +91,7 @@ Feature: request spec When I run `rspec spec/requests/widget_management_spec.rb` Then the example should pass - Scenario: using engine route helpers + Scenario: Using engine route helpers Given a file named "spec/requests/widgets_spec.rb" with: """ruby require "rails_helper" @@ -140,7 +118,7 @@ Feature: request spec end module MyEngine - RSpec.describe "Links", :type => :request do + RSpec.describe "Links", type: :request do include Engine.routes.url_helpers it "redirects to a random widget" do @@ -153,7 +131,7 @@ Feature: request spec When I run `rspec spec` Then the example should pass - Scenario: testing subdomain constrained requests + Scenario: Testing subdomain constrained requests Given a file named "spec/requests/widgets_spec.rb" with: """ruby require "rails_helper" @@ -162,7 +140,7 @@ Feature: request spec resources :widgets, constraints: { subdomain: "api" } end - RSpec.describe "Widget management", :type => :request do + RSpec.describe "Widget management", type: :request do before { host! "api.example.com" } it "creates a Widget" do diff --git a/features/routing_specs/README.md b/features/routing_specs/README.md index c0c4bc3ee1..fc8922be93 100644 --- a/features/routing_specs/README.md +++ b/features/routing_specs/README.md @@ -1,4 +1,6 @@ -Routing specs are marked by `:type => :routing` or if you have set +# Routing specs + +Routing specs are marked by `type: :routing` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/routing`. Simple apps with nothing but standard RESTful routes won't get much value from diff --git a/features/routing_specs/be_routable_matcher.feature b/features/routing_specs/be_routable_matcher.feature index 75c18a82bb..8468eaef53 100644 --- a/features/routing_specs/be_routable_matcher.feature +++ b/features/routing_specs/be_routable_matcher.feature @@ -1,15 +1,15 @@ -Feature: be_routable matcher +Feature: `be_routable` matcher The `be_routable` matcher is best used with `should_not` to specify that a given route should not be routable. It is available in routing specs (in spec/routing) and controller specs (in spec/controllers). - Scenario: specify routeable route should not be routable (fails) + Scenario: Specify routeable route should not be routable (fails) Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "does not route to widgets" do expect(:get => "/widgets").not_to be_routable end @@ -19,12 +19,12 @@ Feature: be_routable matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the output should contain "1 example, 1 failure" - Scenario: specify non-routeable route should not be routable (passes) + Scenario: Specify non-routeable route should not be routable (passes) Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "does not route to widgets/foo/bar" do expect(:get => "/widgets/foo/bar").not_to be_routable end @@ -34,12 +34,12 @@ Feature: be_routable matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the examples should all pass - Scenario: specify routeable route should be routable (passes) + Scenario: Specify routeable route should be routable (passes) Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes to /widgets" do expect(:get => "/widgets").to be_routable end @@ -49,12 +49,12 @@ Feature: be_routable matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the examples should all pass - Scenario: specify non-routeable route should be routable (fails) + Scenario: Specify non-routeable route should be routable (fails) Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes to widgets/foo/bar" do expect(:get => "/widgets/foo/bar").to be_routable end @@ -64,12 +64,12 @@ Feature: be_routable matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the output should contain "1 example, 1 failure" - Scenario: be_routable in a controller spec + Scenario: Use `be_routable` in a controller spec Given a file named "spec/controllers/widgets_controller_spec.rb" with: """ruby require "rails_helper" - RSpec.describe WidgetsController, :type => :controller do + RSpec.describe WidgetsController, type: :controller do it "routes to /widgets" do expect(:get => "/widgets").to be_routable end diff --git a/features/routing_specs/engine_routes.feature b/features/routing_specs/engine_routes.feature index dfa9764fbe..6eb806c735 100644 --- a/features/routing_specs/engine_routes.feature +++ b/features/routing_specs/engine_routes.feature @@ -1,9 +1,9 @@ -Feature: engine routes +Feature: Using engine routes Routing specs can specify the routeset that will be used for the example group. This is most useful when testing Rails engines. - Scenario: specify engine route + Scenario: Specify engine routes Given a file named "spec/routing/engine_routes_spec.rb" with: """ruby require "rails_helper" @@ -24,7 +24,7 @@ Feature: engine routes end end - RSpec.describe MyEngine::WidgetsController, :type => :routing do + RSpec.describe MyEngine::WidgetsController, type: :routing do routes { MyEngine::Engine.routes } it "routes to the list of all widgets" do diff --git a/features/routing_specs/named_routes.feature b/features/routing_specs/named_routes.feature index 64f80a3d92..af8bc61974 100644 --- a/features/routing_specs/named_routes.feature +++ b/features/routing_specs/named_routes.feature @@ -1,13 +1,13 @@ -Feature: named routes +Feature: Using named routes Routing specs have access to named routes. - Scenario: access named route + Scenario: Access named route Given a file named "spec/routing/widget_routes_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes to the widgets controller", :type => :routing do + RSpec.describe "routes to the widgets controller", type: :routing do it "routes a named route" do expect(:get => new_widget_path). to route_to(:controller => "widgets", :action => "new") diff --git a/features/routing_specs/route_to_matcher.feature b/features/routing_specs/route_to_matcher.feature index d23f863287..4253dd3d23 100644 --- a/features/routing_specs/route_to_matcher.feature +++ b/features/routing_specs/route_to_matcher.feature @@ -1,4 +1,4 @@ -Feature: route_to matcher +Feature: `route_to` matcher The `route_to` matcher specifies that a request (verb + path) is routable. It is most valuable when specifying routes other than standard RESTful @@ -10,12 +10,12 @@ Feature: route_to matcher expect(:get => "/").to route_to(:controller => "welcome") - Scenario: passing route spec with shortcut syntax + Scenario: Passing route spec with shortcut syntax Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes /widgets to the widgets controller" do expect(get("/widgets")). to route_to("widgets#index") @@ -26,12 +26,12 @@ Feature: route_to matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the examples should all pass - Scenario: passing route spec with verbose syntax + Scenario: Passing route spec with verbose syntax Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes /widgets to the widgets controller" do expect(:get => "/widgets"). to route_to(:controller => "widgets", :action => "index") @@ -42,12 +42,12 @@ Feature: route_to matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the examples should all pass - Scenario: route spec for a route that doesn't exist (fails) + Scenario: Route spec for a route that doesn't exist (fails) Given a file named "spec/routing/widgets_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes /widgets/foo to the /foo action" do expect(get("/widgets/foo")).to route_to("widgets#foo") end @@ -57,12 +57,12 @@ Feature: route_to matcher When I run `rspec spec/routing/widgets_routing_spec.rb` Then the output should contain "1 failure" - Scenario: route spec for a namespaced route with shortcut specifier + Scenario: Route spec for a namespaced route with shortcut specifier Given a file named "spec/routing/admin_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes /admin/accounts to the admin/accounts controller" do expect(get("/admin/accounts")). to route_to("admin/accounts#index") @@ -73,12 +73,12 @@ Feature: route_to matcher When I run `rspec spec/routing/admin_routing_spec.rb` Then the examples should all pass - Scenario: route spec for a namespaced route with verbose specifier + Scenario: Route spec for a namespaced route with verbose specifier Given a file named "spec/routing/admin_routing_spec.rb" with: """ruby require "rails_helper" - RSpec.describe "routes for Widgets", :type => :routing do + RSpec.describe "routes for Widgets", type: :routing do it "routes /admin/accounts to the admin/accounts controller" do expect(get("/admin/accounts")). to route_to(:controller => "admin/accounts", :action => "index") diff --git a/features/support/env.rb b/features/support/env.rb index 4b30653e93..0eb42150f3 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -36,7 +36,11 @@ def with_unbundled_env World(ArubaExt) Aruba.configure do |config| - config.exit_timeout = 30 + if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'truffleruby' + config.exit_timeout = 120 + else + config.exit_timeout = 30 + end end unless File.directory?('./tmp/example_app') diff --git a/features/support/rails_versions.rb b/features/support/rails_versions.rb index 38d8b6f8c9..95354a0b35 100644 --- a/features/support/rails_versions.rb +++ b/features/support/rails_versions.rb @@ -1,21 +1,14 @@ def rails_version - string_version = ENV.fetch("RAILS_VERSION", "~> 6.0.0") + string_version = ENV.fetch("RAILS_VERSION", "~> 7.0.0") if string_version == "main" || string_version.nil? Float::INFINITY else - string_version[/\d[\.-]\d/].tr('-', '.') + string_version[/\d[.-]\d/].tr('-', '.') end end -Before "@rails_pre_6" do |scenario| - if rails_version.to_f >= 6.0 - warn "Skipping scenario #{scenario.name} on Rails v#{rails_version}" - skip_this_scenario - end -end - -Before "@rails_post_6" do |scenario| - if rails_version.to_f < 6.0 +Before "@rails_post_7" do |scenario| + if rails_version.to_f < 7.0 warn "Skipping scenario #{scenario.name} on Rails v#{rails_version}" skip_this_scenario end diff --git a/features/support/rubinius.rb b/features/support/rubinius.rb deleted file mode 100644 index b09d67abbc..0000000000 --- a/features/support/rubinius.rb +++ /dev/null @@ -1,6 +0,0 @@ -# Required until https://github.com/rubinius/rubinius/issues/2430 is resolved -ENV['RBXOPT'] = "#{ENV['RBXOPT']} -Xcompiler.no_rbc" - -Around "@unsupported-on-rbx" do |_scenario, block| - block.call unless defined?(Rubinius) -end diff --git a/features/system_specs/system_specs.feature b/features/system_specs/system_specs.feature index 2ef93f6e54..bb729ac3f0 100644 --- a/features/system_specs/system_specs.feature +++ b/features/system_specs/system_specs.feature @@ -1,109 +1,109 @@ -Feature: System spec - - System specs are RSpec's wrapper around Rails' own - [system tests](https://guides.rubyonrails.org/testing.html#system-testing). - - > System tests allow you to test user interactions with your application, - > running tests in either a real or a headless browser. System tests use - > Capybara under the hood. - > - > By default, system tests are run with the Selenium driver, using the - > Chrome browser, and a screen size of 1400x1400. The next section explains - > how to change the default settings. - - System specs are marked by setting type to :system, e.g. `:type => :system`. - - The Capybara gem is automatically required, and Rails includes it in - generated application Gemfiles. Configure a webserver (e.g. - `Capybara.server = :webrick`) before attempting to use system specs. - - RSpec **does not** use your `ApplicationSystemTestCase` helper. Instead it - uses the default `driven_by(:selenium)` from Rails. If you want to override - this behaviour you can call `driven_by` manually in a test. - - System specs run in a transaction. So unlike feature specs with - javascript, you do not need [DatabaseCleaner](https://github.com/DatabaseCleaner/database_cleaner). - - @system_test - Scenario: System specs driven by rack_test - Given a file named "spec/system/widget_system_spec.rb" with: - """ruby - require "rails_helper" - - RSpec.describe "Widget management", :type => :system do - before do - driven_by(:rack_test) - end - - it "enables me to create widgets" do - visit "/widgets/new" - - fill_in "Name", :with => "My Widget" - click_button "Create Widget" - - expect(page).to have_text("Widget was successfully created.") - end - end - """ - When I run `rspec spec/system/widget_system_spec.rb` - Then the exit status should be 0 - And the output should contain "1 example, 0 failures" - - @system_test - Scenario: the ActiveJob queue_adapter can be changed - Given a file named "spec/system/some_job_system_spec.rb" with: +Feature: System specs + + System specs are RSpec's wrapper around Rails' own + [system tests](https://guides.rubyonrails.org/testing.html#system-testing). + + > System tests allow you to test user interactions with your application, + > running tests in either a real or a headless browser. System tests use + > Capybara under the hood. + > + > By default, system tests are run with the Selenium driver, using the + > Chrome browser, and a screen size of 1400x1400. The next section explains + > how to change the default settings. + + System specs are marked by setting type to :system, e.g. `type: :system`. + + The Capybara gem is automatically required, and Rails includes it in + generated application Gemfiles. Configure a webserver (e.g. + `Capybara.server = :webrick`) before attempting to use system specs. + + RSpec **does not** use your `ApplicationSystemTestCase` helper. Instead it + uses the default `driven_by(:selenium)` from Rails. If you want to override + this behaviour you can call `driven_by` manually in a test. + + System specs run in a transaction. So unlike feature specs with + javascript, you do not need [DatabaseCleaner](https://github.com/DatabaseCleaner/database_cleaner). + + @system_test + Scenario: System specs driven by rack_test + Given a file named "spec/system/widget_system_spec.rb" with: """ruby require "rails_helper" - class SomeJob < ActiveJob::Base - cattr_accessor :job_ran + RSpec.describe "Widget management", type: :system do + before do + driven_by(:rack_test) + end + + it "enables me to create widgets" do + visit "/widgets/new" + + fill_in "Name", :with => "My Widget" + click_button "Create Widget" - def perform - @@job_ran = true + expect(page).to have_text("Widget was successfully created.") end end + """ + When I run `rspec spec/system/widget_system_spec.rb` + Then the exit status should be 0 + And the output should contain "1 example, 0 failures" + + @system_test + Scenario: The ActiveJob queue_adapter can be changed + Given a file named "spec/system/some_job_system_spec.rb" with: + """ruby + require "rails_helper" + + class SomeJob < ActiveJob::Base + cattr_accessor :job_ran - RSpec.describe "spec/system/some_job_system_spec.rb", :type => :system do - describe "#perform_later" do - before do - ActiveJob::Base.queue_adapter = :inline - end + def perform + @@job_ran = true + end + end + + RSpec.describe "spec/system/some_job_system_spec.rb", type: :system do + describe "#perform_later" do + before do + ActiveJob::Base.queue_adapter = :inline + end + + it "perform later SomeJob" do + expect(ActiveJob::Base.queue_adapter).to be_an_instance_of(ActiveJob::QueueAdapters::InlineAdapter) + + SomeJob.perform_later + + expect(SomeJob.job_ran).to eq(true) + end + end + end + """ + When I run `rspec spec/system/some_job_system_spec.rb` + Then the example should pass + + @system_test + Scenario: System specs driven by selenium_chrome_headless + Given a file named "spec/system/widget_system_spec.rb" with: + """ruby + require "rails_helper" + + RSpec.describe "Widget management", type: :system do + before do + driven_by(:selenium_chrome_headless) + end - it "perform later SomeJob" do - expect(ActiveJob::Base.queue_adapter).to be_an_instance_of(ActiveJob::QueueAdapters::InlineAdapter) + it "enables me to create widgets" do + visit "/widgets/new" - SomeJob.perform_later + fill_in "Name", :with => "My Widget" + click_button "Create Widget" - expect(SomeJob.job_ran).to eq(true) - end + expect(page).to have_text("Widget was successfully created.") end end """ - When I run `rspec spec/system/some_job_system_spec.rb` - Then the example should pass - - @system_test - Scenario: System specs driven by selenium_chrome_headless - Given a file named "spec/system/widget_system_spec.rb" with: - """ruby - require "rails_helper" - - RSpec.describe "Widget management", :type => :system do - before do - driven_by(:selenium_chrome_headless) - end - - it "enables me to create widgets" do - visit "/widgets/new" - - fill_in "Name", :with => "My Widget" - click_button "Create Widget" - - expect(page).to have_text("Widget was successfully created.") - end - end - """ - When I run `rspec spec/system/widget_system_spec.rb` - Then the output should contain "1 example, 0 failures" - And the output should not contain "starting Puma" - And the exit status should be 0 + When I run `rspec spec/system/widget_system_spec.rb` + Then the output should contain "1 example, 0 failures" + And the output should not contain "starting Puma" + And the exit status should be 0 diff --git a/features/upgrade/README.md b/features/upgrade/README.md index 029861fdd9..5947fb0842 100644 --- a/features/upgrade/README.md +++ b/features/upgrade/README.md @@ -1,3 +1,9 @@ +# Upgrading from rspec-rails 5.x to version 6 + +RSpec Rails 6 is a major version under semantic versioning, it also follows our new versioning strategy for RSpec-Rails, which is to keep in step with Rails supported versions. Thus it supports 6.1 and 7.0. There are no changes required to upgrade to RSpec Rails 6 if you are using a supported version of Rails. + +If you are using an older version of Rails, you can use 5.x which hard supports 5.2 and 6.x. + # Upgrading from rspec-rails 4.x to version 5 RSpec Rails 5 is a major version under semantic versioning, it also follows our new versioning strategy for RSpec-Rails, which is to keep in step with Rails supported versions. Thus it supports 5.2, 6.0 and 6.1. There are no changes required to upgrade to RSpec Rails 5 if you are using a supported version of Rails. @@ -10,4 +16,4 @@ RSpec Rails 4 is a major version under semantic versioning, it allowed us to cha If you are using Rails 4.2 you can use RSpec Rails 4, but note that support for it is not maintained, we consider this a breaking change hence the version change, and you must be on Ruby 2.2 as a minimum. -If you are upgrading from an earlier version of RSpec Rails, please consult [the upgrading 2.x to 3.x guide](https://relishapp.com/rspec/rspec-rails/v/3-9/docs/upgrade). +If you are upgrading from an earlier version of RSpec Rails, please consult [the upgrading 2.x to 3.x guide](https://web.archive.org/web/20220124160827/https://relishapp.com/rspec/rspec-rails/v/3-9/docs/upgrade). diff --git a/features/view_specs/inferred_controller_path.feature b/features/view_specs/inferred_controller_path.feature index bc9e7abd9e..90c14dbbec 100644 --- a/features/view_specs/inferred_controller_path.feature +++ b/features/view_specs/inferred_controller_path.feature @@ -1,6 +1,6 @@ -Feature: view spec infers controller path and action +Feature: View specs infer controller's path and action - Scenario: infer controller path + Scenario: Infer controller path Given a file named "spec/views/widgets/new.html.erb_spec.rb" with: """ruby require "rails_helper" @@ -15,7 +15,7 @@ Feature: view spec infers controller path and action When I run `rspec spec/views` Then the examples should all pass - Scenario: infer action + Scenario: Infer action Given a file named "spec/views/widgets/new.html.erb_spec.rb" with: """ruby require "rails_helper" @@ -29,7 +29,7 @@ Feature: view spec infers controller path and action When I run `rspec spec/views` Then the examples should all pass - Scenario: do not infer action in a partial + Scenario: Do not infer action in a partial Given a file named "spec/views/widgets/_form.html.erb_spec.rb" with: """ruby require "rails_helper" @@ -42,4 +42,3 @@ Feature: view spec infers controller path and action """ When I run `rspec spec/views` Then the examples should all pass - diff --git a/features/view_specs/stub_template.feature b/features/view_specs/stub_template.feature index 46e5381f35..72fe757982 100644 --- a/features/view_specs/stub_template.feature +++ b/features/view_specs/stub_template.feature @@ -1,9 +1,9 @@ -Feature: stub template +Feature: Using `stub_template` In order to isolate view specs from the partials rendered by the primary view, rspec-rails (since 2.2) provides the stub_template method. - Scenario: stub template that does not exist + Scenario: Stub a template that does not exist Given a file named "spec/views/gadgets/list.html.erb_spec.rb" with: """ruby require "rails_helper" @@ -29,7 +29,7 @@ Feature: stub template When I run `rspec spec/views/gadgets/list.html.erb_spec.rb` Then the examples should all pass - Scenario: stub template that exists + Scenario: Stub a template that exists Given a file named "spec/views/gadgets/edit.html.erb_spec.rb" with: """ruby require "rails_helper" @@ -48,4 +48,3 @@ Feature: stub template """ When I run `rspec spec/views/gadgets/edit.html.erb_spec.rb` Then the examples should all pass - diff --git a/features/view_specs/view_spec.feature b/features/view_specs/view_spec.feature index 76f99846b1..518b57e6f6 100644 --- a/features/view_specs/view_spec.feature +++ b/features/view_specs/view_spec.feature @@ -1,6 +1,6 @@ -Feature: view spec +Feature: View specs - View specs are marked by `:type => :view` + View specs are marked by `type: :view` or if you have set `config.infer_spec_type_from_file_location!` by placing them in `spec/views`. diff --git a/lib/generators/rspec.rb b/lib/generators/rspec.rb index ae9e9df084..e1ff5429a5 100644 --- a/lib/generators/rspec.rb +++ b/lib/generators/rspec.rb @@ -1,8 +1,9 @@ require 'rails/generators/named_base' +require 'rspec/core' require 'rspec/rails/feature_check' # @private -# Weirdly named generators namespace (should be `RSpec`) for compatability with +# Weirdly named generators namespace (should be `RSpec`) for compatibility with # rails loading. module Rspec # @private @@ -18,6 +19,22 @@ def self.source_root(path = nil) @_rspec_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'rspec', generator_name, 'templates')) end end + + # @private + # Load configuration from RSpec to ensure `--default-path` is set + def self.configuration + @configuration ||= + begin + configuration = RSpec.configuration + options = RSpec::Core::ConfigurationOptions.new({}) + options.configure(configuration) + configuration + end + end + + def target_path(*paths) + File.join(self.class.configuration.default_path, *paths) + end end end end diff --git a/lib/generators/rspec/channel/channel_generator.rb b/lib/generators/rspec/channel/channel_generator.rb index 1e1937bc99..55b86a826d 100644 --- a/lib/generators/rspec/channel/channel_generator.rb +++ b/lib/generators/rspec/channel/channel_generator.rb @@ -5,7 +5,7 @@ module Generators # @private class ChannelGenerator < Base def create_channel_spec - template 'channel_spec.rb.erb', File.join('spec/channels', class_path, "#{file_name}_channel_spec.rb") + template 'channel_spec.rb.erb', target_path('channels', class_path, "#{file_name}_channel_spec.rb") end end end diff --git a/lib/generators/rspec/controller/controller_generator.rb b/lib/generators/rspec/controller/controller_generator.rb index 4111a9aabb..c55e093d87 100644 --- a/lib/generators/rspec/controller/controller_generator.rb +++ b/lib/generators/rspec/controller/controller_generator.rb @@ -16,14 +16,14 @@ def generate_request_spec return unless options[:request_specs] template 'request_spec.rb', - File.join('spec/requests', class_path, "#{file_name}_spec.rb") + target_path('requests', class_path, "#{file_name}_spec.rb") end def generate_controller_spec return unless options[:controller_specs] template 'controller_spec.rb', - File.join('spec/controllers', class_path, "#{file_name}_controller_spec.rb") + target_path('controllers', class_path, "#{file_name}_controller_spec.rb") end def generate_view_specs @@ -35,7 +35,7 @@ def generate_view_specs actions.each do |action| @action = action template 'view_spec.rb', - File.join("spec", "views", file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb") + target_path('views', file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb") end end @@ -44,7 +44,7 @@ def generate_routing_spec return unless options[:routing_specs] template 'routing_spec.rb', - File.join('spec/routing', class_path, "#{file_name}_routing_spec.rb") + target_path('routing', class_path, "#{file_name}_routing_spec.rb") end end end diff --git a/lib/generators/rspec/feature/feature_generator.rb b/lib/generators/rspec/feature/feature_generator.rb index 5b9bfc4675..4e383d3cb5 100644 --- a/lib/generators/rspec/feature/feature_generator.rb +++ b/lib/generators/rspec/feature/feature_generator.rb @@ -10,7 +10,7 @@ class FeatureGenerator < Base def generate_feature_spec return unless options[:feature_specs] - template template_name, File.join('spec/features', class_path, filename) + template template_name, target_path('features', class_path, filename) end def template_name diff --git a/lib/generators/rspec/generator/generator_generator.rb b/lib/generators/rspec/generator/generator_generator.rb index 9d73d2ddc5..40118e83a2 100644 --- a/lib/generators/rspec/generator/generator_generator.rb +++ b/lib/generators/rspec/generator/generator_generator.rb @@ -9,7 +9,7 @@ class GeneratorGenerator < Base def generate_generator_spec return unless options[:generator_specs] - template template_name, File.join('spec/generator', class_path, filename) + template template_name, target_path('generator', class_path, filename) end def template_name diff --git a/lib/generators/rspec/helper/helper_generator.rb b/lib/generators/rspec/helper/helper_generator.rb index a035f8e4a7..dd820c7dfc 100644 --- a/lib/generators/rspec/helper/helper_generator.rb +++ b/lib/generators/rspec/helper/helper_generator.rb @@ -9,7 +9,7 @@ class HelperGenerator < Base def generate_helper_spec return unless options[:helper_specs] - template 'helper_spec.rb', File.join('spec/helpers', class_path, "#{file_name}_helper_spec.rb") + template 'helper_spec.rb', target_path('helpers', class_path, "#{file_name}_helper_spec.rb") end end end diff --git a/lib/generators/rspec/install/install_generator.rb b/lib/generators/rspec/install/install_generator.rb index 8b832089d3..1bd4a23cb3 100644 --- a/lib/generators/rspec/install/install_generator.rb +++ b/lib/generators/rspec/install/install_generator.rb @@ -12,6 +12,8 @@ class InstallGenerator < ::Rails::Generators::Base Copy rspec files to your application. DESC + class_option :default_path, type: :string, default: 'spec' + def self.source_root @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates')) end @@ -20,12 +22,12 @@ def copy_spec_files Dir.mktmpdir do |dir| generate_rspec_init dir template File.join(dir, '.rspec'), '.rspec' - directory File.join(dir, 'spec'), 'spec' + directory File.join(dir, 'spec'), default_path end end def copy_rails_files - template 'spec/rails_helper.rb' + template 'spec/rails_helper.rb', "#{default_path}/rails_helper.rb" end private @@ -41,6 +43,12 @@ def generate_rspec_init(tmpdir) replace_generator_command(spec_helper_path) remove_warnings_configuration(spec_helper_path) + + unless default_path == "spec" + dot_rspec_path = File.join(tmpdir, '.rspec') + + append_default_path(dot_rspec_path) + end end def replace_generator_command(spec_helper_path) @@ -58,6 +66,15 @@ def remove_warnings_configuration(spec_helper_path) '', verbose: false end + + def append_default_path(dot_rspec_path) + append_to_file dot_rspec_path, + "--default-path #{default_path}" + end + + def default_path + options[:default_path] + end end end end diff --git a/lib/generators/rspec/install/templates/spec/rails_helper.rb b/lib/generators/rspec/install/templates/spec/rails_helper.rb index c9882fe56a..f943c7b267 100644 --- a/lib/generators/rspec/install/templates/spec/rails_helper.rb +++ b/lib/generators/rspec/install/templates/spec/rails_helper.rb @@ -48,7 +48,7 @@ # Remove this line to enable support for ActiveRecord config.use_active_record = false - # If you enable ActiveRecord support you should unncomment these lines, + # If you enable ActiveRecord support you should uncomment these lines, # note if you'd prefer not to run each example within a transaction, you # should set use_transactional_fixtures to false. # @@ -68,7 +68,7 @@ # end # # The different available types are documented in the features, such as in - # https://relishapp.com/rspec/rspec-rails/docs + # https://rspec.info/features/6-0/rspec-rails config.infer_spec_type_from_file_location! # Filter lines from Rails gems in backtraces. diff --git a/lib/generators/rspec/integration/integration_generator.rb b/lib/generators/rspec/integration/integration_generator.rb index f820b017f9..ed281e832e 100644 --- a/lib/generators/rspec/integration/integration_generator.rb +++ b/lib/generators/rspec/integration/integration_generator.rb @@ -1,21 +1,28 @@ require 'generators/rspec' +require 'rspec/core/warnings' module Rspec module Generators # @private class IntegrationGenerator < Base - # Add a deprecation for this class, before rspec-rails 4, to use the - # `RequestGenerator` instead class_option :request_specs, type: :boolean, default: true, desc: "Generate request specs" + source_paths << File.expand_path('../request/templates', __dir__) + def generate_request_spec return unless options[:request_specs] + RSpec.warn_deprecation <<-WARNING.gsub(/\s*\|/, ' ') + |The integration generator is deprecated + |and will be deleted in RSpec-Rails 7. + |Please use the request generator instead. + WARNING + template 'request_spec.rb', - File.join('spec/requests', "#{name.underscore.pluralize}_spec.rb") + target_path('requests', "#{name.underscore.pluralize}_spec.rb") end end end diff --git a/lib/generators/rspec/job/job_generator.rb b/lib/generators/rspec/job/job_generator.rb index 1d167856b8..06196797bb 100644 --- a/lib/generators/rspec/job/job_generator.rb +++ b/lib/generators/rspec/job/job_generator.rb @@ -6,7 +6,7 @@ module Generators class JobGenerator < Base def create_job_spec file_suffix = file_name.end_with?('job') ? 'spec.rb' : 'job_spec.rb' - template 'job_spec.rb.erb', File.join('spec/jobs', class_path, [file_name, file_suffix].join('_')) + template 'job_spec.rb.erb', target_path('jobs', class_path, [file_name, file_suffix].join('_')) end end end diff --git a/lib/generators/rspec/mailbox/mailbox_generator.rb b/lib/generators/rspec/mailbox/mailbox_generator.rb index 1277326e3b..601c892115 100644 --- a/lib/generators/rspec/mailbox/mailbox_generator.rb +++ b/lib/generators/rspec/mailbox/mailbox_generator.rb @@ -6,7 +6,7 @@ module Generators class MailboxGenerator < Base def create_mailbox_spec template('mailbox_spec.rb.erb', - File.join('spec/mailboxes', class_path, "#{file_name}_mailbox_spec.rb") + target_path('mailboxes', class_path, "#{file_name}_mailbox_spec.rb") ) end end diff --git a/lib/generators/rspec/mailer/mailer_generator.rb b/lib/generators/rspec/mailer/mailer_generator.rb index 0030dbffe4..7aeb10eeac 100644 --- a/lib/generators/rspec/mailer/mailer_generator.rb +++ b/lib/generators/rspec/mailer/mailer_generator.rb @@ -8,20 +8,20 @@ class MailerGenerator < Base argument :actions, type: :array, default: [], banner: "method method" def generate_mailer_spec - template "mailer_spec.rb", File.join('spec/mailers', class_path, "#{file_name}_spec.rb") + template "mailer_spec.rb", target_path('mailers', class_path, "#{file_name}_spec.rb") end def generate_fixtures_files actions.each do |action| @action, @path = action, File.join(file_path, action) - template "fixture", File.join("spec/fixtures", @path) + template "fixture", target_path("fixtures", @path) end end def generate_preview_files return unless RSpec::Rails::FeatureCheck.has_action_mailer_preview? - template "preview.rb", File.join("spec/mailers/previews", class_path, "#{file_name}_preview.rb") + template "preview.rb", target_path("mailers/previews", class_path, "#{file_name}_preview.rb") end end end diff --git a/lib/generators/rspec/model/model_generator.rb b/lib/generators/rspec/model/model_generator.rb index 6ab0ffb666..3b757ce59e 100644 --- a/lib/generators/rspec/model/model_generator.rb +++ b/lib/generators/rspec/model/model_generator.rb @@ -11,8 +11,8 @@ class ModelGenerator < Base class_option :fixture, type: :boolean def create_model_spec - template_file = File.join( - 'spec/models', + template_file = target_path( + 'models', class_path, "#{file_name}_spec.rb" ) @@ -24,7 +24,7 @@ def create_model_spec def create_fixture_file return unless missing_fixture_replacement? - template 'fixtures.yml', File.join('spec/fixtures', class_path, "#{(pluralize_table_names? ? plural_file_name : file_name)}.yml") + template 'fixtures.yml', target_path('fixtures', class_path, "#{(pluralize_table_names? ? plural_file_name : file_name)}.yml") end private diff --git a/lib/generators/rspec/request/request_generator.rb b/lib/generators/rspec/request/request_generator.rb index b9e15f3ada..b6114e1e3b 100644 --- a/lib/generators/rspec/request/request_generator.rb +++ b/lib/generators/rspec/request/request_generator.rb @@ -1,10 +1,17 @@ -require 'generators/rspec/integration/integration_generator' +require 'generators/rspec' module Rspec module Generators # @private - class RequestGenerator < IntegrationGenerator - source_paths << File.expand_path('../integration/templates', __dir__) + class RequestGenerator < Base + class_option :request_specs, type: :boolean, default: true, desc: 'Generate request specs' + + def generate_request_spec + return unless options[:request_specs] + + template 'request_spec.rb', + target_path('requests', "#{name.underscore.pluralize}_spec.rb") + end end end end diff --git a/lib/generators/rspec/integration/templates/request_spec.rb b/lib/generators/rspec/request/templates/request_spec.rb similarity index 100% rename from lib/generators/rspec/integration/templates/request_spec.rb rename to lib/generators/rspec/request/templates/request_spec.rb diff --git a/lib/generators/rspec/scaffold/scaffold_generator.rb b/lib/generators/rspec/scaffold/scaffold_generator.rb index 23987555f2..7e0af83ee0 100644 --- a/lib/generators/rspec/scaffold/scaffold_generator.rb +++ b/lib/generators/rspec/scaffold/scaffold_generator.rb @@ -58,8 +58,8 @@ def generate_view_specs def generate_routing_spec return unless options[:routing_specs] - template_file = File.join( - 'spec/routing', + template_file = target_path( + 'routing', controller_class_path, "#{controller_file_name}_routing_spec.rb" ) @@ -72,7 +72,7 @@ def generate_routing_spec def copy_view(view) template "#{view}_spec.rb", - File.join("spec/views", controller_file_path, "#{view}.html.#{options[:template_engine]}_spec.rb") + target_path("views", controller_file_path, "#{view}.html.#{options[:template_engine]}_spec.rb") end # support for namespaced-resources @@ -121,7 +121,7 @@ def raw_value_for(attribute) end def template_file(folder:, suffix: '') - File.join('spec', folder, controller_class_path, "#{controller_file_name}#{suffix}_spec.rb") + target_path(folder, controller_class_path, "#{controller_file_name}#{suffix}_spec.rb") end def banner diff --git a/lib/generators/rspec/scaffold/templates/api_controller_spec.rb b/lib/generators/rspec/scaffold/templates/api_controller_spec.rb index 7dc7889bf4..c8e519d5fc 100644 --- a/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +++ b/lib/generators/rspec/scaffold/templates/api_controller_spec.rb @@ -100,7 +100,7 @@ it "renders a JSON response with the <%= singular_table_name %>" do <%= file_name %> = <%= class_name %>.create! valid_attributes - put :update, params: {id: <%= file_name %>.to_param, <%= singular_table_name %>: valid_attributes}, session: valid_session + put :update, params: {id: <%= file_name %>.to_param, <%= singular_table_name %>: new_attributes}, session: valid_session expect(response).to have_http_status(:ok) expect(response.content_type).to eq('application/json') end diff --git a/lib/generators/rspec/scaffold/templates/controller_spec.rb b/lib/generators/rspec/scaffold/templates/controller_spec.rb index fe19a35185..7f4320bd06 100644 --- a/lib/generators/rspec/scaffold/templates/controller_spec.rb +++ b/lib/generators/rspec/scaffold/templates/controller_spec.rb @@ -119,7 +119,7 @@ it "redirects to the <%= singular_table_name %>" do <%= file_name %> = <%= class_name %>.create! valid_attributes - put :update, params: {id: <%= file_name %>.to_param, <%= singular_table_name %>: valid_attributes}, session: valid_session + put :update, params: {id: <%= file_name %>.to_param, <%= singular_table_name %>: new_attributes}, session: valid_session expect(response).to redirect_to(<%= file_name %>) end end diff --git a/lib/generators/rspec/scaffold/templates/edit_spec.rb b/lib/generators/rspec/scaffold/templates/edit_spec.rb index 959f1cfd27..fdbc3043df 100644 --- a/lib/generators/rspec/scaffold/templates/edit_spec.rb +++ b/lib/generators/rspec/scaffold/templates/edit_spec.rb @@ -2,18 +2,22 @@ <% output_attributes = attributes.reject{|attribute| [:datetime, :timestamp, :time, :date].index(attribute.type) } -%> RSpec.describe "<%= ns_table_name %>/edit", <%= type_metatag(:view) %> do - before(:each) do - @<%= ns_file_name %> = assign(:<%= ns_file_name %>, <%= class_name %>.create!(<%= '))' if output_attributes.empty? %> + let(:<%= singular_table_name %>) { + <%= class_name %>.create!(<%= ')' if output_attributes.empty? %> <% output_attributes.each_with_index do |attribute, attribute_index| -%> <%= attribute.name %>: <%= attribute.default.inspect %><%= attribute_index == output_attributes.length - 1 ? '' : ','%> <% end -%> -<%= output_attributes.empty? ? "" : " ))\n" -%> +<%= " )\n" unless output_attributes.empty? -%> + } + + before(:each) do + assign(:<%= singular_table_name %>, <%= singular_table_name %>) end it "renders the edit <%= ns_file_name %> form" do render - assert_select "form[action=?][method=?]", <%= ns_file_name %>_path(@<%= ns_file_name %>), "post" do + assert_select "form[action=?][method=?]", <%= ns_file_name %>_path(<%= singular_table_name %>), "post" do <% for attribute in output_attributes -%> <%- name = attribute.respond_to?(:column_name) ? attribute.column_name : attribute.name %> assert_select "<%= attribute.input_type -%>[name=?]", "<%= ns_file_name %>[<%= name %>]" diff --git a/lib/generators/rspec/scaffold/templates/new_spec.rb b/lib/generators/rspec/scaffold/templates/new_spec.rb index db52126462..320dbe5693 100644 --- a/lib/generators/rspec/scaffold/templates/new_spec.rb +++ b/lib/generators/rspec/scaffold/templates/new_spec.rb @@ -3,7 +3,7 @@ <% output_attributes = attributes.reject{|attribute| [:datetime, :timestamp, :time, :date].index(attribute.type) } -%> RSpec.describe "<%= ns_table_name %>/new", <%= type_metatag(:view) %> do before(:each) do - assign(:<%= ns_file_name %>, <%= class_name %>.new(<%= '))' if output_attributes.empty? %> + assign(:<%= singular_table_name %>, <%= class_name %>.new(<%= '))' if output_attributes.empty? %> <% output_attributes.each_with_index do |attribute, attribute_index| -%> <%= attribute.name %>: <%= attribute.default.inspect %><%= attribute_index == output_attributes.length - 1 ? '' : ','%> <% end -%> diff --git a/lib/generators/rspec/scaffold/templates/show_spec.rb b/lib/generators/rspec/scaffold/templates/show_spec.rb index 15811dea5a..523201530b 100644 --- a/lib/generators/rspec/scaffold/templates/show_spec.rb +++ b/lib/generators/rspec/scaffold/templates/show_spec.rb @@ -3,7 +3,7 @@ <% output_attributes = attributes.reject{|attribute| [:datetime, :timestamp, :time, :date].index(attribute.type) } -%> RSpec.describe "<%= ns_table_name %>/show", <%= type_metatag(:view) %> do before(:each) do - @<%= ns_file_name %> = assign(:<%= ns_file_name %>, <%= class_name %>.create!(<%= '))' if output_attributes.empty? %> + assign(:<%= singular_table_name %>, <%= class_name %>.create!(<%= '))' if output_attributes.empty? %> <% output_attributes.each_with_index do |attribute, attribute_index| -%> <%= attribute.name %>: <%= value_for(attribute) %><%= attribute_index == output_attributes.length - 1 ? '' : ','%> <% end -%> diff --git a/lib/generators/rspec/system/system_generator.rb b/lib/generators/rspec/system/system_generator.rb index 4735632e90..6f3667a208 100644 --- a/lib/generators/rspec/system/system_generator.rb +++ b/lib/generators/rspec/system/system_generator.rb @@ -9,7 +9,7 @@ class SystemGenerator < Base def generate_system_spec return unless options[:system_specs] - template template_name, File.join('spec/system', class_path, filename) + template template_name, target_path('system', class_path, filename) end def template_name diff --git a/lib/generators/rspec/view/view_generator.rb b/lib/generators/rspec/view/view_generator.rb index 5de24267e5..75c9b2619a 100644 --- a/lib/generators/rspec/view/view_generator.rb +++ b/lib/generators/rspec/view/view_generator.rb @@ -9,12 +9,12 @@ class ViewGenerator < Base class_option :template_engine, desc: "Template engine to generate view files" def create_view_specs - empty_directory File.join("spec", "views", file_path) + empty_directory target_path("views", file_path) actions.each do |action| @action = action template 'view_spec.rb', - File.join("spec", "views", file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb") + target_path("views", file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb") end end end diff --git a/lib/rspec-rails.rb b/lib/rspec-rails.rb index 361c777df7..45592fbd87 100644 --- a/lib/rspec-rails.rb +++ b/lib/rspec-rails.rb @@ -8,11 +8,7 @@ module Rails class Railtie < ::Rails::Railtie # As of Rails 5.1.0 you can register directories to work with `rake notes` require 'rails/source_annotation_extractor' - if ::Rails::VERSION::STRING >= '6.0' - ::Rails::SourceAnnotationExtractor::Annotation.register_directories("spec") - else - SourceAnnotationExtractor::Annotation.register_directories("spec") - end + ::Rails::SourceAnnotationExtractor::Annotation.register_directories("spec") generators = config.app_generators generators.integration_tool :rspec generators.test_framework :rspec diff --git a/lib/rspec/rails/adapters.rb b/lib/rspec/rails/adapters.rb index 1990b797e4..74bee1c85e 100644 --- a/lib/rspec/rails/adapters.rb +++ b/lib/rspec/rails/adapters.rb @@ -181,5 +181,16 @@ def assertion_delegator # # @private TestUnitAssertionAdapter = MinitestAssertionAdapter + + # @private + module TaggedLoggingAdapter + private + # Vendored from activesupport/lib/active_support/testing/tagged_logging.rb + # This implements the tagged_logger method where it is expected, but + # doesn't call `name` or set it up like Rails does. + def tagged_logger + @tagged_logger ||= (defined?(Rails.logger) && Rails.logger) + end + end end end diff --git a/lib/rspec/rails/configuration.rb b/lib/rspec/rails/configuration.rb index 6f781ba1ef..20d4cf3a4a 100644 --- a/lib/rspec/rails/configuration.rb +++ b/lib/rspec/rails/configuration.rb @@ -26,18 +26,19 @@ class Configuration # # @api private DIRECTORY_MAPPINGS = { - channel: %w[spec channels], + channel: %w[spec channels], controller: %w[spec controllers], - helper: %w[spec helpers], - job: %w[spec jobs], - mailer: %w[spec mailers], - model: %w[spec models], - request: %w[spec (requests|integration|api)], - routing: %w[spec routing], - view: %w[spec views], - feature: %w[spec features], - system: %w[spec system], - mailbox: %w[spec mailboxes] + generator: %w[spec generator], + helper: %w[spec helpers], + job: %w[spec jobs], + mailer: %w[spec mailers], + model: %w[spec models], + request: %w[spec (requests|integration|api)], + routing: %w[spec routing], + view: %w[spec views], + feature: %w[spec features], + system: %w[spec system], + mailbox: %w[spec mailboxes] } # Sets up the different example group modules for the different spec types diff --git a/lib/rspec/rails/example/rails_example_group.rb b/lib/rspec/rails/example/rails_example_group.rb index 3a3ecbe704..0643b9ae17 100644 --- a/lib/rspec/rails/example/rails_example_group.rb +++ b/lib/rspec/rails/example/rails_example_group.rb @@ -2,6 +2,10 @@ # suite and ammeter. require 'rspec/rails/matchers' +if ::Rails::VERSION::MAJOR >= 7 + require 'active_support/execution_context/test_helper' +end + module RSpec module Rails # @api public @@ -12,6 +16,10 @@ module RailsExampleGroup include RSpec::Rails::MinitestLifecycleAdapter include RSpec::Rails::MinitestAssertionAdapter include RSpec::Rails::FixtureSupport + if ::Rails::VERSION::MAJOR >= 7 + include RSpec::Rails::TaggedLoggingAdapter + include ActiveSupport::ExecutionContext::TestHelper + end end end end diff --git a/lib/rspec/rails/example/system_example_group.rb b/lib/rspec/rails/example/system_example_group.rb index e0f395bce0..530c8976ea 100644 --- a/lib/rspec/rails/example/system_example_group.rb +++ b/lib/rspec/rails/example/system_example_group.rb @@ -44,6 +44,52 @@ def method_name ].join("_").tr(CHARS_TO_TRANSLATE.join, "_").byteslice(0...200).scrub("") + "_#{rand(1000)}" end + if ::Rails::VERSION::STRING.to_f >= 7.1 + # @private + # Allows failure screenshot to work whilst not exposing metadata + class SuppressRailsScreenshotMetadata + def initialize + @example_data = {} + end + + def [](key) + if @example_data.key?(key) + @example_data[key] + else + raise_wrong_scope_error + end + end + + def []=(key, value) + if key == :failure_screenshot_path + @example_data[key] = value + else + raise_wrong_scope_error + end + end + + def method_missing(_name, *_args, &_block) + raise_wrong_scope_error + end + + private + + def raise_wrong_scope_error + raise RSpec::Core::ExampleGroup::WrongScopeError, + "`metadata` is not available from within an example " \ + "(e.g. an `it` block) or from constructs that run in the " \ + "scope of an example (e.g. `before`, `let`, etc). It is " \ + "only available on an example group (e.g. a `describe` or "\ + "`context` block)" + end + end + + # @private + def metadata + @metadata ||= SuppressRailsScreenshotMetadata.new + end + end + # Delegates to `Rails.application`. def app ::Rails.application @@ -54,23 +100,22 @@ def app ActionDispatch::SystemTesting::Server.silence_puma = true end + require 'action_dispatch/system_test_case' + begin require 'capybara' - require 'action_dispatch/system_test_case' rescue LoadError => e abort """ LoadError: #{e.message} - System test integration requires Rails >= 5.1 and has a hard + System test integration has a hard dependency on a webserver and `capybara`, please add capybara to your Gemfile and configure a webserver (e.g. `Capybara.server = - :webrick`) before attempting to use system specs. + :puma`) before attempting to use system specs. """.gsub(/\s+/, ' ').strip end - if ::Rails::VERSION::STRING >= '6.0' - original_before_teardown = - ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:before_teardown) - end + original_before_teardown = + ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:before_teardown) original_after_teardown = ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:after_teardown) @@ -108,10 +153,7 @@ def driven_by(driver, **driver_options, &blk) orig_stdout = $stdout $stdout = StringIO.new begin - if ::Rails::VERSION::STRING >= '6.0' - original_before_teardown.bind(self).call - end - original_after_teardown.bind(self).call + original_before_teardown.bind(self).call ensure myio = $stdout myio.rewind @@ -119,6 +161,11 @@ def driven_by(driver, **driver_options, &blk) $stdout = orig_stdout end end + + around do |example| + example.run + original_after_teardown.bind(self).call + end end end end diff --git a/lib/rspec/rails/example/view_example_group.rb b/lib/rspec/rails/example/view_example_group.rb index 76783582dd..49d05a373d 100644 --- a/lib/rspec/rails/example/view_example_group.rb +++ b/lib/rspec/rails/example/view_example_group.rb @@ -89,7 +89,7 @@ def view # # stub_template("widgets/_widget.html.erb" => "This content.") def stub_template(hash) - view.view_paths.unshift(StubResolverCache.resolver_for(hash)) + controller.prepend_view_path(StubResolverCache.resolver_for(hash)) end # Provides access to the params hash that will be available within the @@ -149,7 +149,7 @@ def _default_render_options # the original string. match = path_regex.match(_default_file_to_render) - render_options = {template: match[:template]} + render_options = { template: match[:template] } render_options[:handlers] = [match[:handler].to_sym] if match[:handler] render_options[:formats] = [match[:format].to_sym] if match[:format] render_options[:locales] = [match[:locale].to_sym] if match[:locale] diff --git a/lib/rspec/rails/feature_check.rb b/lib/rspec/rails/feature_check.rb index 4a4d855d75..a19b2cfef2 100644 --- a/lib/rspec/rails/feature_check.rb +++ b/lib/rspec/rails/feature_check.rb @@ -24,7 +24,7 @@ def has_action_mailer_preview? end def has_action_cable_testing? - defined?(::ActionCable) && ActionCable::VERSION::MAJOR >= 6 + defined?(::ActionCable) end def has_action_mailer_parameterized? diff --git a/lib/rspec/rails/file_fixture_support.rb b/lib/rspec/rails/file_fixture_support.rb index 45059a38d1..85745c6e39 100644 --- a/lib/rspec/rails/file_fixture_support.rb +++ b/lib/rspec/rails/file_fixture_support.rb @@ -9,6 +9,9 @@ module FileFixtureSupport included do self.file_fixture_path = RSpec.configuration.file_fixture_path + if defined?(ActiveStorage::FixtureSet) + ActiveStorage::FixtureSet.file_fixture_path = RSpec.configuration.file_fixture_path + end end end end diff --git a/lib/rspec/rails/fixture_file_upload_support.rb b/lib/rspec/rails/fixture_file_upload_support.rb index ef4989c653..c321728504 100644 --- a/lib/rspec/rails/fixture_file_upload_support.rb +++ b/lib/rspec/rails/fixture_file_upload_support.rb @@ -6,41 +6,24 @@ module FixtureFileUploadSupport private - # In Rails 6.2 fixture file path needs to be relative to `file_fixture_path` instead, this change - # was brought in with a deprecation warning on 6.1. In Rails 6.2 expect to rework this to remove + # In Rails 7.0 fixture file path needs to be relative to `file_fixture_path` instead, this change + # was brought in with a deprecation warning on 6.1. In Rails 7.0 expect to rework this to remove # the old accessor. - if ::Rails.version.to_f >= 6.1 - def rails_fixture_file_wrapper - RailsFixtureFileWrapper.file_fixture_path = nil - resolved_fixture_path = - if respond_to?(:file_fixture_path) && !file_fixture_path.nil? - file_fixture_path.to_s - else - (RSpec.configuration.fixture_path || '').to_s - end - RailsFixtureFileWrapper.file_fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty? - RailsFixtureFileWrapper.instance - end - else - def rails_fixture_file_wrapper - RailsFixtureFileWrapper.fixture_path = nil - resolved_fixture_path = - if respond_to?(:fixture_path) && !fixture_path.nil? - fixture_path.to_s - else - (RSpec.configuration.fixture_path || '').to_s - end - RailsFixtureFileWrapper.fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty? - RailsFixtureFileWrapper.instance - end + def rails_fixture_file_wrapper + RailsFixtureFileWrapper.file_fixture_path = nil + resolved_fixture_path = + if respond_to?(:file_fixture_path) && !file_fixture_path.nil? + file_fixture_path.to_s + else + (RSpec.configuration.fixture_path || '').to_s + end + RailsFixtureFileWrapper.file_fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty? + RailsFixtureFileWrapper.instance end class RailsFixtureFileWrapper include ActionDispatch::TestProcess if defined?(ActionDispatch::TestProcess) - - if ::Rails.version.to_f >= 6.1 - include ActiveSupport::Testing::FileFixtures - end + include ActiveSupport::Testing::FileFixtures class << self attr_accessor :fixture_path diff --git a/lib/rspec/rails/fixture_support.rb b/lib/rspec/rails/fixture_support.rb index 7624cb3648..703bc87847 100644 --- a/lib/rspec/rails/fixture_support.rb +++ b/lib/rspec/rails/fixture_support.rb @@ -21,7 +21,12 @@ def run_in_transaction? if RSpec.configuration.use_active_record? include Fixtures - self.fixture_path = RSpec.configuration.fixture_path + # TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2 + if respond_to?(:fixture_paths=) + fixture_paths << RSpec.configuration.fixture_path + else + self.fixture_path = RSpec.configuration.fixture_path + end self.use_transactional_tests = RSpec.configuration.use_transactional_fixtures self.use_instantiated_fixtures = RSpec.configuration.use_instantiated_fixtures @@ -32,28 +37,50 @@ def run_in_transaction? module Fixtures extend ActiveSupport::Concern + # rubocop:disable Metrics/BlockLength class_methods do - def fixtures(*args) - orig_methods = private_instance_methods - super.tap do - new_methods = private_instance_methods - orig_methods - new_methods.each do |method_name| - proxy_method_warning_if_called_in_before_context_scope(method_name) + if ::Rails.version.to_f >= 7.1 + def fixtures(*args) + super.tap do + fixture_sets.each_key do |fixture_name| + proxy_method_warning_if_called_in_before_context_scope(fixture_name) + end + end + end + + def proxy_method_warning_if_called_in_before_context_scope(fixture_name) + define_method(fixture_name) do |*args, **kwargs, &blk| + if RSpec.current_scope == :before_context_hook + RSpec.warn_with("Calling fixture method in before :context ") + else + access_fixture(fixture_name, *args, **kwargs, &blk) + end + end + end + else + def fixtures(*args) + orig_methods = private_instance_methods + super.tap do + new_methods = private_instance_methods - orig_methods + new_methods.each do |method_name| + proxy_method_warning_if_called_in_before_context_scope(method_name) + end end end - end - def proxy_method_warning_if_called_in_before_context_scope(method_name) - orig_implementation = instance_method(method_name) - define_method(method_name) do |*args, &blk| - if RSpec.current_scope == :before_context_hook - RSpec.warn_with("Calling fixture method in before :context ") - else - orig_implementation.bind(self).call(*args, &blk) + def proxy_method_warning_if_called_in_before_context_scope(method_name) + orig_implementation = instance_method(method_name) + define_method(method_name) do |*args, &blk| + if RSpec.current_scope == :before_context_hook + RSpec.warn_with("Calling fixture method in before :context ") + else + orig_implementation.bind(self).call(*args, &blk) + end end end end end + # rubocop:enable Metrics/BlockLength end end end diff --git a/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb b/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb index 98b0d7d201..297d7cfcf3 100644 --- a/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +++ b/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb @@ -96,8 +96,11 @@ def from_channel(channel) private def stream - @stream ||= if @target.is_a?(String) + @stream ||= case @target + when String @target + when Symbol + @target.to_s else check_channel_presence @channel.broadcasting_for(@target) @@ -109,7 +112,7 @@ def check(messages) decoded = ActiveSupport::JSON.decode(msg) decoded = decoded.with_indifferent_access if decoded.is_a?(Hash) - if @data.nil? || @data === decoded + if @data.nil? || values_match?(@data, decoded) @block.call(decoded) true else @@ -159,7 +162,7 @@ def pubsub_adapter def check_channel_presence return if @channel.present? && @channel.respond_to?(:channel_name) - error_msg = "Broadcasting channel can't be infered. Please, specify it with `from_channel`" + error_msg = "Broadcasting channel can't be inferred. Please, specify it with `from_channel`" raise ArgumentError, error_msg end end diff --git a/lib/rspec/rails/matchers/active_job.rb b/lib/rspec/rails/matchers/active_job.rb index 217503a52e..944391032c 100644 --- a/lib/rspec/rails/matchers/active_job.rb +++ b/lib/rspec/rails/matchers/active_job.rb @@ -181,7 +181,7 @@ def check_for_inprecise_value(scheduled_at) |`Time.current.change(usec: 0)` | |Note: RSpec cannot do this for you because jobs can be scheduled with usec - |precision and we do not know wether it is on purpose or not. + |precision and we do not know whether it is on purpose or not. | | WARNING @@ -230,11 +230,11 @@ def initialize(job) def matches?(proc) raise ArgumentError, "have_enqueued_job and enqueue_job only support block expectations" unless Proc === proc - original_enqueued_jobs_count = queue_adapter.enqueued_jobs.count + original_enqueued_jobs = Set.new(queue_adapter.enqueued_jobs) proc.call - in_block_jobs = queue_adapter.enqueued_jobs.drop(original_enqueued_jobs_count) + enqueued_jobs = Set.new(queue_adapter.enqueued_jobs) - check(in_block_jobs) + check(enqueued_jobs - original_enqueued_jobs) end def does_not_match?(proc) diff --git a/lib/rspec/rails/matchers/have_enqueued_mail.rb b/lib/rspec/rails/matchers/have_enqueued_mail.rb index 1d2b16a203..fcd3c64d71 100644 --- a/lib/rspec/rails/matchers/have_enqueued_mail.rb +++ b/lib/rspec/rails/matchers/have_enqueued_mail.rb @@ -134,7 +134,7 @@ def mail_job_message(job) end # Ruby 3.1 changed how params were serialized on Rails 6.1 - # so we override the active job implementation and customise it here. + # so we override the active job implementation and customize it here. def deserialize_arguments(job) args = super diff --git a/lib/rspec/rails/matchers/have_http_status.rb b/lib/rspec/rails/matchers/have_http_status.rb index e39cde44c2..858ef547b6 100644 --- a/lib/rspec/rails/matchers/have_http_status.rb +++ b/lib/rspec/rails/matchers/have_http_status.rb @@ -305,7 +305,7 @@ def check_expected_status(test_response, expected) private - # @return [String] formating the expected status and associated code(s) + # @return [String] formatting the expected status and associated code(s) def type_message @type_message ||= (expected == :error ? "an error" : "a #{expected}") + " status code (#{type_codes})" diff --git a/lib/rspec/rails/matchers/routing_matchers.rb b/lib/rspec/rails/matchers/routing_matchers.rb index e2b209addd..621b06b00e 100644 --- a/lib/rspec/rails/matchers/routing_matchers.rb +++ b/lib/rspec/rails/matchers/routing_matchers.rb @@ -26,7 +26,7 @@ def matches?(verb_to_path_map) path, query = *verb_to_path_map.values.first.split('?') @scope.assert_recognizes( @expected, - {method: verb_to_path_map.keys.first, path: path}, + { method: verb_to_path_map.keys.first, path: path }, Rack::Utils.parse_nested_query(query) ) end @@ -115,7 +115,7 @@ module RouteHelpers # Shorthand method for matching this type of route. %w[get post put patch delete options head].each do |method| define_method method do |path| - {method.to_sym => path} + { method.to_sym => path } end end end diff --git a/lib/rspec/rails/vendor/capybara.rb b/lib/rspec/rails/vendor/capybara.rb index c6c735869a..97f8eb64e6 100644 --- a/lib/rspec/rails/vendor/capybara.rb +++ b/lib/rspec/rails/vendor/capybara.rb @@ -12,9 +12,7 @@ RSpec.configure do |c| if defined?(Capybara::DSL) c.include Capybara::DSL, type: :feature - if defined?(ActionPack) && ActionPack::VERSION::STRING >= "5.1" - c.include Capybara::DSL, type: :system - end + c.include Capybara::DSL, type: :system end if defined?(Capybara::RSpecMatchers) diff --git a/lib/rspec/rails/version.rb b/lib/rspec/rails/version.rb index 3b7b7aa263..a371bc4a5f 100644 --- a/lib/rspec/rails/version.rb +++ b/lib/rspec/rails/version.rb @@ -3,7 +3,7 @@ module Rails # Version information for RSpec Rails. module Version # Current version of RSpec Rails, in semantic versioning format. - STRING = '6.0.0.pre' + STRING = '6.0.4' end end end diff --git a/lib/rspec/rails/view_assigns.rb b/lib/rspec/rails/view_assigns.rb index e8bbb5fa75..2b9d05fa0c 100644 --- a/lib/rspec/rails/view_assigns.rb +++ b/lib/rspec/rails/view_assigns.rb @@ -13,26 +13,8 @@ def assign(key, value) end # Compat-shim for AbstractController::Rendering#view_assigns - # - # _assigns was deprecated in favor of view_assigns after - # Rails-3.0.0 was released. Since we are not able to predict when - # the _assigns/view_assigns patch will be released (I thought it - # would have been in 3.0.1, but 3.0.1 bypassed this change for a - # security fix), this bit ensures that we do the right thing without - # knowing anything about the Rails version we are dealing with. - # - # Once that change _is_ released, this can be changed to something - # that checks for the Rails version when the module is being - # interpreted, as it was before commit dd0095. def view_assigns super.merge(_encapsulated_assigns) - rescue - _assigns - end - - # @private - def _assigns - super.merge(_encapsulated_assigns) end private diff --git a/lib/rspec/rails/view_rendering.rb b/lib/rspec/rails/view_rendering.rb index 22eff75ba2..feca67acbc 100644 --- a/lib/rspec/rails/view_rendering.rb +++ b/lib/rspec/rails/view_rendering.rb @@ -62,14 +62,8 @@ def self.nullify_template_rendering(templates) end end - if ::Rails::VERSION::STRING >= '6' - def self.template_format(template) - template.format - end - else - def self.template_format(template) - template.formats - end + def self.template_format(template) + template.format end # Delegates all methods to the submitted resolver and for all methods @@ -77,7 +71,15 @@ def self.template_format(template) # templates with modified source # # @private - class ResolverDecorator + class ResolverDecorator < ::ActionView::Resolver + (::ActionView::Resolver.instance_methods - Object.instance_methods).each do |method| + undef_method method + end + + (::ActionView::Resolver.methods - Object.methods).each do |method| + singleton_class.undef_method method + end + def initialize(resolver) @resolver = resolver end @@ -125,11 +127,11 @@ def self.call(_template, _source = nil) # @private module EmptyTemplates def prepend_view_path(new_path) - lookup_context.view_paths.unshift(*_path_decorator(*new_path)) + super(_path_decorator(*new_path)) end def append_view_path(new_path) - lookup_context.view_paths.push(*_path_decorator(*new_path)) + super(_path_decorator(*new_path)) end private diff --git a/rfcs/versioning-strategy.md b/rfcs/versioning-strategy.md index d757b03451..a380220c3b 100644 --- a/rfcs/versioning-strategy.md +++ b/rfcs/versioning-strategy.md @@ -8,7 +8,7 @@ This RFC captures a proposal for RSpec Rails' new versioning strategy. Specifica ## Need -Currently, the RSpec Rails [build matrix](https://travis-ci.org/rspec/rspec-rails) +Currently, the RSpec Rails build matrix has 63 entries. This permutes rubies since 1.8.7 and Rails versions since 3.0. As of right now the full build takes over an hour to run, and this makes cycling for PRs and quick iterative development very difficult. diff --git a/rspec-rails.gemspec b/rspec-rails.gemspec index d285a90080..f295abfad4 100644 --- a/rspec-rails.gemspec +++ b/rspec-rails.gemspec @@ -46,17 +46,17 @@ Gem::Specification.new do |s| # get released. %w[core expectations mocks support].each do |name| if ENV['RSPEC_CI'] - s.add_runtime_dependency "rspec-#{name}", ENV.fetch('RSPEC_VERSION', '3.12.0.pre') + s.add_runtime_dependency "rspec-#{name}", ENV.fetch('RSPEC_VERSION', '3.13.0.pre') elsif RSpec::Rails::Version::STRING =~ /pre/ # prerelease builds - expected_rspec_version = "3.12.0.pre" + expected_rspec_version = "3.13.0.pre" s.add_runtime_dependency "rspec-#{name}", "= #{expected_rspec_version}" else - expected_rspec_version = "3.11.0" + expected_rspec_version = "3.12.0" s.add_runtime_dependency "rspec-#{name}", "~> #{expected_rspec_version.split(".")[0..1].join(".")}" end end s.add_development_dependency 'ammeter', '~> 1.1.5' s.add_development_dependency 'aruba', '~> 0.14.12' - s.add_development_dependency 'cucumber', '>= 3.2', '!= 4.0.0', '< 8.0.0' + s.add_development_dependency 'cucumber', '~> 7.0' end diff --git a/script/functions.sh b/script/functions.sh index 145fe378f1..702d785bf6 100644 --- a/script/functions.sh +++ b/script/functions.sh @@ -38,7 +38,7 @@ function run_specs_and_record_done { function run_cukes { if [ -d features ]; then - # force jRuby to use client mode JVM or a compilation mode thats as close as possible, + # force jRuby to use client mode JVM or a compilation mode that's as close as possible, # idea taken from https://github.com/jruby/jruby/wiki/Improving-startup-time # # Note that we delay setting this until we run the cukes because we've seen diff --git a/script/predicate_functions.sh b/script/predicate_functions.sh index 1a3198801d..90067bb10b 100644 --- a/script/predicate_functions.sh +++ b/script/predicate_functions.sh @@ -57,6 +57,14 @@ function is_mri_2plus { fi } +function is_ruby_26_plus { + if ruby -e "exit(RUBY_VERSION.to_f >= 2.6)"; then + return 0 + else + return 1 + fi +} + function is_ruby_23_plus { if ruby -e "exit(RUBY_VERSION.to_f >= 2.3)"; then return 0 diff --git a/script/update_rubygems_and_install_bundler b/script/update_rubygems_and_install_bundler index 3cfe3a4565..4c386c945b 100755 --- a/script/update_rubygems_and_install_bundler +++ b/script/update_rubygems_and_install_bundler @@ -5,9 +5,13 @@ set -e source script/functions.sh -if is_ruby_23_plus; then +if is_ruby_26_plus; then gem update --no-document --system gem install --no-document bundler +elif is_ruby_23_plus; then + echo "Warning installing older versions of Rubygems / Bundler" + gem update --system '3.3.26' + gem install bundler -v '2.3.26' else echo "Warning installing older versions of Rubygems / Bundler" gem update --system '2.7.10' diff --git a/snippets/avoid_fixture_name_collision.rb b/snippets/avoid_fixture_name_collision.rb index 8f1768acc8..047d5c218d 100644 --- a/snippets/avoid_fixture_name_collision.rb +++ b/snippets/avoid_fixture_name_collision.rb @@ -20,7 +20,6 @@ # Those Gemfiles carefully pick the right versions depending on # settings in the ENV, `.rails-version` and `maintenance-branch`. Dir.chdir('..') do - eval_gemfile 'Gemfile-sqlite-dependencies' # This Gemfile expects `maintenance-branch` file to be present # in the current directory. eval_gemfile 'Gemfile-rspec-dependencies' diff --git a/snippets/include_activesupport_testing_tagged_logger.rb b/snippets/include_activesupport_testing_tagged_logger.rb new file mode 100644 index 0000000000..c8d87caf34 --- /dev/null +++ b/snippets/include_activesupport_testing_tagged_logger.rb @@ -0,0 +1,70 @@ +if __FILE__ =~ /^snippets/ + fail "Snippets are supposed to be run from their own directory to avoid side " \ + "effects as e.g. the root `Gemfile`, or `spec/spec_helpers.rb` to be " \ + "loaded by the root `.rspec`." +end + +# We opt-out from using RubyGems, but `bundler/inline` requires it +require 'rubygems' + +require "bundler/inline" + +# We pass `false` to `gemfile` to skip the installation of gems, +# because it may install versions that would conflict with versions +# from the main `Gemfile.lock`. +gemfile(false) do + source "https://rubygems.org" + + git_source(:github) { |repo| "https://github.com/#{repo}.git" } + + # Those Gemfiles carefully pick the right versions depending on + # settings in the ENV, `.rails-version` and `maintenance-branch`. + Dir.chdir('..') do + # This Gemfile expects `maintenance-branch` file to be present + # in the current directory. + eval_gemfile 'Gemfile-rspec-dependencies' + # This Gemfile expects `.rails-version` file + eval_gemfile 'Gemfile-rails-dependencies' + end + + gem "rspec-rails", path: "../" +end + +# Run specs at exit +require "rspec/autorun" + +require "rails" +require "active_record/railtie" +require "active_job/railtie" +require "rspec/rails" + +ActiveJob::Base.queue_adapter = :test + +# This connection will do for database-independent bug reports +ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") + +class TestError < StandardError; end + +class TestJob < ActiveJob::Base + def perform + raise TestError + end +end + +RSpec.describe 'Foo', type: :job do + include ::ActiveJob::TestHelper + + describe 'error raised in perform_enqueued_jobs with block' do + it 'raises the explicitly thrown error' do + # Rails 6.1+ wraps unexpected errors in tests + expected_error = if Rails::VERSION::STRING.to_f >= 6.1 + Minitest::UnexpectedError.new(TestError) + else + TestError + end + + expect { perform_enqueued_jobs { TestJob.perform_later } } + .to raise_error(expected_error) + end + end +end diff --git a/snippets/use_active_record_false.rb b/snippets/use_active_record_false.rb index 2965223084..705af8a394 100644 --- a/snippets/use_active_record_false.rb +++ b/snippets/use_active_record_false.rb @@ -20,7 +20,6 @@ # Those Gemfiles carefully pick the right versions depending on # settings in the ENV, `.rails-version` and `maintenance-branch`. Dir.chdir('..') do - eval_gemfile 'Gemfile-sqlite-dependencies' # This Gemfile expects `maintenance-branch` file to be present # in the current directory. eval_gemfile 'Gemfile-rspec-dependencies' diff --git a/spec/generators/rspec/feature/feature_generator_spec.rb b/spec/generators/rspec/feature/feature_generator_spec.rb index 335ef335a3..352bf76179 100644 --- a/spec/generators/rspec/feature/feature_generator_spec.rb +++ b/spec/generators/rspec/feature/feature_generator_spec.rb @@ -19,7 +19,7 @@ expect(feature_spec).to contain(/require 'rails_helper'/) end it "contains the feature" do - expect(feature_spec).to contain(/^RSpec.feature \"Posts\", #{type_metatag(:feature)}/) + expect(feature_spec).to contain(/^RSpec.feature "Posts", #{type_metatag(:feature)}/) end end end @@ -34,7 +34,7 @@ expect(feature_spec).to exist end it "contains the feature" do - expect(feature_spec).to contain(/^RSpec.feature \"Folder::Posts\", #{type_metatag(:feature)}/) + expect(feature_spec).to contain(/^RSpec.feature "Folder::Posts", #{type_metatag(:feature)}/) end end end @@ -49,7 +49,7 @@ expect(feature_spec).to exist end it "contains the singularized feature" do - expect(feature_spec).to contain(/^RSpec.feature \"Post\", #{type_metatag(:feature)}/) + expect(feature_spec).to contain(/^RSpec.feature "Post", #{type_metatag(:feature)}/) end end end diff --git a/spec/generators/rspec/generator/generator_generator_spec.rb b/spec/generators/rspec/generator/generator_generator_spec.rb index be70da8434..2d416e0bba 100644 --- a/spec/generators/rspec/generator/generator_generator_spec.rb +++ b/spec/generators/rspec/generator/generator_generator_spec.rb @@ -16,7 +16,7 @@ expect(generator_spec).to contain(/require 'rails_helper'/) end it "includes the generator type in the metadata" do - expect(generator_spec).to contain(/^RSpec.describe \"Posts\", #{type_metatag(:generator)}/) + expect(generator_spec).to contain(/^RSpec.describe "Posts", #{type_metatag(:generator)}/) end end end diff --git a/spec/generators/rspec/integration/integration_generator_spec.rb b/spec/generators/rspec/integration/integration_generator_spec.rb index ac8ffe16a2..e0777bb85b 100644 --- a/spec/generators/rspec/integration/integration_generator_spec.rb +++ b/spec/generators/rspec/integration/integration_generator_spec.rb @@ -1,8 +1,14 @@ # Generators are not automatically loaded by Rails require 'generators/rspec/integration/integration_generator' require 'support/generators' +require 'rspec/core/warnings' RSpec.describe Rspec::Generators::IntegrationGenerator, type: :generator do setup_default_destination it_behaves_like "a request spec generator" + + it 'is deprecated' do + expect(RSpec).to receive(:warn_deprecation) + run_generator %w[posts] + end end diff --git a/spec/generators/rspec/scaffold/scaffold_generator_spec.rb b/spec/generators/rspec/scaffold/scaffold_generator_spec.rb index dfd1a5aff4..4ca4c4f705 100644 --- a/spec/generators/rspec/scaffold/scaffold_generator_spec.rb +++ b/spec/generators/rspec/scaffold/scaffold_generator_spec.rb @@ -192,6 +192,7 @@ it { is_expected.to exist } it { is_expected.to contain(/require 'rails_helper'/) } it { is_expected.to contain(/^RSpec.describe "(.*)\/edit", #{type_metatag(:view)}/) } + it { is_expected.to contain(/assign\(:post, post\)/) } it { is_expected.to contain(/it "renders the edit (.*) form"/) } end @@ -200,6 +201,7 @@ it { is_expected.to exist } it { is_expected.to contain(/require 'rails_helper'/) } it { is_expected.to contain(/^RSpec.describe "(.*)\/index", #{type_metatag(:view)}/) } + it { is_expected.to contain(/assign\(:posts, /) } it { is_expected.to contain(/it "renders a list of (.*)"/) } end @@ -208,6 +210,7 @@ it { is_expected.to exist } it { is_expected.to contain(/require 'rails_helper'/) } it { is_expected.to contain(/^RSpec.describe "(.*)\/new", #{type_metatag(:view)}/) } + it { is_expected.to contain(/assign\(:post, /) } it { is_expected.to contain(/it "renders new (.*) form"/) } end @@ -216,6 +219,7 @@ it { is_expected.to exist } it { is_expected.to contain(/require 'rails_helper'/) } it { is_expected.to contain(/^RSpec.describe "(.*)\/show", #{type_metatag(:view)}/) } + it { is_expected.to contain(/assign\(:post, /) } it { is_expected.to contain(/it "renders attributes in

"/) } end end @@ -251,6 +255,62 @@ end end + describe 'with namespace' do + before { run_generator %w[admin/posts] } + + describe 'edit' do + subject { file("spec/views/admin/posts/edit.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:admin_post, admin_post\)/) } + end + + describe 'index' do + subject { file("spec/views/admin/posts/index.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:admin_posts, /) } + end + + describe 'new' do + subject { file("spec/views/admin/posts/new.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:admin_post, /) } + end + + describe 'show' do + subject { file("spec/views/admin/posts/show.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:admin_post, /) } + end + end + + describe 'with namespace and --model-name' do + before { run_generator %w[admin/posts --model-name=Post] } + + describe 'edit' do + subject { file("spec/views/admin/posts/edit.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:post, post\)/) } + end + + describe 'index' do + subject { file("spec/views/admin/posts/index.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:posts, /) } + end + + describe 'new' do + subject { file("spec/views/admin/posts/new.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:post, /) } + end + + describe 'show' do + subject { file("spec/views/admin/posts/show.html.erb_spec.rb") } + it { is_expected.to exist } + it { is_expected.to contain(/assign\(:post, /) } + end + end + describe 'with --no-template-engine' do before { run_generator %w[posts --no-template-engine] } describe 'edit' do diff --git a/spec/generators/rspec/system/system_generator_spec.rb b/spec/generators/rspec/system/system_generator_spec.rb index 884665e2e7..0d2fc35474 100644 --- a/spec/generators/rspec/system/system_generator_spec.rb +++ b/spec/generators/rspec/system/system_generator_spec.rb @@ -19,7 +19,7 @@ expect(system_spec).to contain(/require 'rails_helper'/) end it "contains the system" do - expect(system_spec).to contain(/^RSpec.describe \"Posts\", #{type_metatag(:system)}/) + expect(system_spec).to contain(/^RSpec.describe "Posts", #{type_metatag(:system)}/) end end end diff --git a/spec/generators/rspec/view/view_generator_spec.rb b/spec/generators/rspec/view/view_generator_spec.rb index 45fe89b582..87bc185764 100644 --- a/spec/generators/rspec/view/view_generator_spec.rb +++ b/spec/generators/rspec/view/view_generator_spec.rb @@ -10,7 +10,7 @@ run_generator %w[posts index] file('spec/views/posts/index.html.erb_spec.rb').tap do |f| expect(f).to contain(/require 'rails_helper'/) - expect(f).to contain(/^RSpec.describe \"posts\/index\", #{type_metatag(:view)}/) + expect(f).to contain(/^RSpec.describe "posts\/index", #{type_metatag(:view)}/) end end @@ -19,7 +19,7 @@ run_generator %w[admin/posts index] file('spec/views/admin/posts/index.html.erb_spec.rb').tap do |f| expect(f).to contain(/require 'rails_helper'/) - expect(f).to contain(/^RSpec.describe \"admin\/posts\/index\", #{type_metatag(:view)}/) + expect(f).to contain(/^RSpec.describe "admin\/posts\/index", #{type_metatag(:view)}/) end end end @@ -30,7 +30,7 @@ run_generator %w[posts index --template_engine haml] file('spec/views/posts/index.html.haml_spec.rb').tap do |f| expect(f).to contain(/require 'rails_helper'/) - expect(f).to contain(/^RSpec.describe \"posts\/index\", #{type_metatag(:view)}/) + expect(f).to contain(/^RSpec.describe "posts\/index", #{type_metatag(:view)}/) end end end diff --git a/spec/rspec/rails/configuration_spec.rb b/spec/rspec/rails/configuration_spec.rb index b3601ad9fc..e38e6e8011 100644 --- a/spec/rspec/rails/configuration_spec.rb +++ b/spec/rspec/rails/configuration_spec.rb @@ -93,7 +93,7 @@ end describe "`#render_views=`" do - it "sets `render_views?` to the truthyness of the provided value" do + it "sets `render_views?` to the truthiness of the provided value" do expect { config.render_views = :a_value }.to change { config.render_views? }.from(false).to(true) @@ -164,13 +164,19 @@ def in_inferring_type_from_location_environment group = RSpec.describe("Arbitrary Description", :use_fixtures) - expect(group).to respond_to(:fixture_path) - expect(group.fixture_path).to eq("custom/path") + if ::Rails::VERSION::STRING < '7.1.0' + expect(group).to respond_to(:fixture_path) + expect(group.fixture_path).to eq("custom/path") + else + expect(group).to respond_to(:fixture_paths) + expect(group.fixture_paths).to include("custom/path") + end + expect(group.new.respond_to?(:foo, true)).to be(true) end end - it "metadata `:type => :controller` sets up controller example groups" do + it "metadata `type: :controller` sets up controller example groups" do a_controller_class = Class.new stub_const "SomeController", a_controller_class diff --git a/spec/rspec/rails/example/rails_example_group_spec.rb b/spec/rspec/rails/example/rails_example_group_spec.rb new file mode 100644 index 0000000000..7faac16468 --- /dev/null +++ b/spec/rspec/rails/example/rails_example_group_spec.rb @@ -0,0 +1,36 @@ +module RSpec::Rails + RSpec.describe RailsExampleGroup do + if ::Rails::VERSION::MAJOR >= 7 + it 'supports tagged_logger' do + expect(described_class.private_instance_methods).to include(:tagged_logger) + end + end + + it 'does not leak context between example groups', if: ::Rails::VERSION::MAJOR >= 7 do + groups = + [ + RSpec::Core::ExampleGroup.describe("A group") do + include RSpec::Rails::RailsExampleGroup + specify { expect(ActiveSupport::ExecutionContext.to_h).to eq({}) } + end, + RSpec::Core::ExampleGroup.describe("A controller group", type: :controller) do + specify do + Rails.error.set_context(foo: "bar") + expect(ActiveSupport::ExecutionContext.to_h).to eq(foo: "bar") + end + end, + RSpec::Core::ExampleGroup.describe("Another group") do + include RSpec::Rails::RailsExampleGroup + specify { expect(ActiveSupport::ExecutionContext.to_h).to eq({}) } + end + ] + + results = + groups.map do |group| + group.run(failure_reporter) ? true : failure_reporter.exceptions + end + + expect(results).to all be true + end + end +end diff --git a/spec/rspec/rails/example/system_example_group_spec.rb b/spec/rspec/rails/example/system_example_group_spec.rb index cdc135946a..9ec9773840 100644 --- a/spec/rspec/rails/example/system_example_group_spec.rb +++ b/spec/rspec/rails/example/system_example_group_spec.rb @@ -91,5 +91,85 @@ def take_screenshot expect(example.metadata[:extra_failure_lines]).to eq(["line 1\n", "line 2\n"]) end end + + describe '#take_screenshot', if: ::Rails::VERSION::STRING.to_f >= 7.1 do + it 'handles Rails calling metadata' do + allow(Capybara::Session).to receive(:instance_created?).and_return(true) + group = RSpec::Core::ExampleGroup.describe do + include SystemExampleGroup + + before do + driven_by(:selenium) + end + + def page + instance_double(Capybara::Session, save_screenshot: nil) + end + end + example = group.it('fails') { raise } + group.run + + expect(example.metadata[:execution_result].exception).to be_a RuntimeError + end + end + + describe '#metadata', if: ::Rails::VERSION::STRING.to_f >= 7.1 do + let(:group) do + RSpec::Core::ExampleGroup.describe do + include SystemExampleGroup + end + end + + it 'fakes out the rails expected method' do + example = group.it('does nothing') { + metadata[:failure_screenshot_path] = :value + expect(metadata[:failure_screenshot_path]).to eq(:value) + } + group.run + expect(example.execution_result.status).to eq :passed + end + + it 'still raises correctly if you use it for something else' do + examples = [] + examples << group.it('fails nothing') { metadata[:other] = :value } + examples << group.it('fails nothing') { metadata[:other] } + examples << group.it('fails nothing') { metadata.key?(:any) } + group.run + expect(examples.map(&:execution_result)).to all have_attributes status: :failed + end + end + + describe "hook order" do + it 'calls Capybara.reset_sessions (TestUnit after_teardown) after any after hooks' do + calls_in_order = [] + allow(Capybara).to receive(:reset_sessions!) { calls_in_order << :reset_sessions! } + + group = RSpec::Core::ExampleGroup.describe do + include SystemExampleGroup + + before do + driven_by(:selenium) + end + + after do + calls_in_order << :after_hook + end + + append_after do + calls_in_order << :append_after_hook + end + + around do |example| + example.run + calls_in_order << :around_hook_after_example + end + end + group.it('works') { } + group.run + + expect(calls_in_order).to eq([:after_hook, :append_after_hook, :around_hook_after_example, :reset_sessions!]) + end + + end end end diff --git a/spec/rspec/rails/example/view_example_group_spec.rb b/spec/rspec/rails/example/view_example_group_spec.rb index 5f8ede30cb..7f6629c7c6 100644 --- a/spec/rspec/rails/example/view_example_group_spec.rb +++ b/spec/rspec/rails/example/view_example_group_spec.rb @@ -145,25 +145,25 @@ def _default_file_to_render; end # Stub method it "sends render(:template => (described file)) to the view" do allow(view_spec).to receive(:_default_file_to_render) { "widgets/new" } view_spec.render - expect(view_spec.received.first).to eq([{template: "widgets/new"}, {}, nil]) + expect(view_spec.received.first).to eq([{ template: "widgets/new" }, {}, nil]) end it "converts the filename components into render options" do allow(view_spec).to receive(:_default_file_to_render) { "widgets/new.en.html.erb" } view_spec.render - expect(view_spec.received.first).to eq([{template: "widgets/new", locales: [:en], formats: [:html], handlers: [:erb]}, {}, nil]) + expect(view_spec.received.first).to eq([{ template: "widgets/new", locales: [:en], formats: [:html], handlers: [:erb] }, {}, nil]) end it "converts the filename with variant into render options" do allow(view_spec).to receive(:_default_file_to_render) { "widgets/new.en.html+fancy.erb" } view_spec.render - expect(view_spec.received.first).to eq([{template: "widgets/new", locales: [:en], formats: [:html], handlers: [:erb], variants: [:fancy]}, {}, nil]) + expect(view_spec.received.first).to eq([{ template: "widgets/new", locales: [:en], formats: [:html], handlers: [:erb], variants: [:fancy] }, {}, nil]) end it "converts the filename without format into render options" do allow(view_spec).to receive(:_default_file_to_render) { "widgets/new.en.erb" } view_spec.render - expect(view_spec.received.first).to eq([{template: "widgets/new", locales: [:en], handlers: [:erb]}, {}, nil]) + expect(view_spec.received.first).to eq([{ template: "widgets/new", locales: [:en], handlers: [:erb] }, {}, nil]) end end @@ -177,7 +177,7 @@ def _default_file_to_render; end # Stub method context "given a hash" do it "sends the hash as the first arg to render" do view_spec.render(foo: 'bar') - expect(view_spec.received.first).to eq([{foo: "bar"}, {}, nil]) + expect(view_spec.received.first).to eq([{ foo: "bar" }, {}, nil]) end end end @@ -280,33 +280,65 @@ def _view; end describe '#stub_template' do let(:view_spec_group) do - Class.new do - include ViewExampleGroup::ExampleMethods - def _view - @_view ||= Struct.new(:view_paths).new(['some-path']) - end + RSpec.describe "a view spec" do + include ::RSpec::Rails::ViewExampleGroup end end it 'prepends an ActionView::FixtureResolver to the view path' do - view_spec = view_spec_group.new - view_spec.stub_template('some_path/some_template' => 'stubbed-contents') + result = :not_loaded - result = view_spec.view.view_paths.first + view_spec_group.specify do + stub_template('some_path/some_template' => 'stubbed-contents') + result = view.view_paths.first + end + view_spec_group.run expect(result).to be_instance_of(ActionView::FixtureResolver) data = result.respond_to?(:data) ? result.data : result.hash expect(data).to eq('some_path/some_template' => 'stubbed-contents') end + it 'caches FixtureResolver instances between examples' do + example_one_view_paths = :not_set + example_two_view_paths = :not_set + + view_spec_group.specify do + stub_template('some_path/some_template' => 'stubbed-contents') + example_one_view_paths = view.view_paths + end + view_spec_group.specify do + stub_template('some_path/some_template' => 'stubbed-contents') + example_two_view_paths = view.view_paths + end + view_spec_group.run + + expect(example_one_view_paths.first).to eq(example_two_view_paths.first) + end + it 'caches FixtureResolver instances between example groups' do - view_spec_one = view_spec_group.new - view_spec_two = view_spec_group.new + example_one_view_paths = :not_set + example_two_view_paths = :not_set - view_spec_one.stub_template('some_path/some_template' => 'stubbed-contents') - view_spec_two.stub_template('some_path/some_template' => 'stubbed-contents') + RSpec.describe "a view spec" do + include ::RSpec::Rails::ViewExampleGroup + + specify do + stub_template('some_path/some_template' => 'stubbed-contents') + example_one_view_paths = view.view_paths + end + end.run + + RSpec.describe "another view spec" do + include ::RSpec::Rails::ViewExampleGroup + + specify do + stub_template('some_path/some_template' => 'stubbed-contents') + example_two_view_paths = view.view_paths + end + end.run - expect(view_spec_one.view.view_paths.first).to eq(view_spec_two.view.view_paths.first) + expect(example_one_view_paths.first).to eq(example_two_view_paths.first) end end end diff --git a/spec/rspec/rails/fixture_file_upload_support_spec.rb b/spec/rspec/rails/fixture_file_upload_support_spec.rb index af074704dd..3c5c0bda7c 100644 --- a/spec/rspec/rails/fixture_file_upload_support_spec.rb +++ b/spec/rspec/rails/fixture_file_upload_support_spec.rb @@ -35,11 +35,7 @@ def fixture_file_upload_resolved(fixture_name, fixture_path = nil) RSpec::Core::ExampleGroup.describe do include RSpec::Rails::FixtureFileUploadSupport - if ::Rails.version.to_f >= 6.1 - self.file_fixture_path = fixture_path - else - self.fixture_path = fixture_path - end + self.file_fixture_path = fixture_path it 'supports fixture file upload' do file = fixture_file_upload(fixture_name) diff --git a/spec/rspec/rails/fixture_support_spec.rb b/spec/rspec/rails/fixture_support_spec.rb index 62b08a303f..534a063125 100644 --- a/spec/rspec/rails/fixture_support_spec.rb +++ b/spec/rspec/rails/fixture_support_spec.rb @@ -39,7 +39,7 @@ def expect_to_pass(group) end end - it "will allow #setup_fixture to run successfully", skip: Rails.version.to_f <= 6.0 do + it "will allow #setup_fixture to run successfully" do group = RSpec::Core::ExampleGroup.describe do include FixtureSupport diff --git a/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb b/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb index 7da826eca8..815a9225a8 100644 --- a/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb +++ b/spec/rspec/rails/matchers/action_cable/have_broadcasted_to_spec.rb @@ -50,6 +50,12 @@ def broadcast(stream, msg) }.to have_broadcasted_to('stream') end + it "passes when using symbol target" do + expect { + broadcast(:stream, 'hello') + }.to have_broadcasted_to(:stream) + end + it "passes when using alias" do expect { broadcast('stream', 'hello') @@ -164,6 +170,12 @@ def broadcast(stream, msg) }.to have_broadcasted_to('stream').with(a_hash_including(name: "David", id: 42)) end + it "passes with provided data matchers with anything" do + expect { + broadcast('stream', id: 42, name: "David", message_id: 123) + }.to have_broadcasted_to('stream').with({ name: anything, id: anything, message_id: anything }) + end + it "generates failure message when data not match" do expect { expect { diff --git a/spec/rspec/rails/matchers/action_cable/have_stream_spec.rb b/spec/rspec/rails/matchers/action_cable/have_stream_spec.rb index 92eda28c10..f257d2c9a5 100644 --- a/spec/rspec/rails/matchers/action_cable/have_stream_spec.rb +++ b/spec/rspec/rails/matchers/action_cable/have_stream_spec.rb @@ -98,7 +98,7 @@ def subscribed expect { expect(subscription).to have_stream_from("chat_2") - }.to raise_error(/expected to have stream "chat_2" started, but have \[\"chat_1\"\]/) + }.to raise_error(/expected to have stream "chat_2" started, but have \["chat_1"\]/) end context "with negated form" do @@ -113,7 +113,7 @@ def subscribed expect { expect(subscription).not_to have_stream_from("chat_1") - }.to raise_error(/expected not to have stream "chat_1" started, but have \[\"chat_1\"\]/) + }.to raise_error(/expected not to have stream "chat_1" started, but have \["chat_1"\]/) end end @@ -129,7 +129,7 @@ def subscribed expect { expect(subscription).to have_stream_from(a_string_starting_with("room")) - }.to raise_error(/expected to have stream a string starting with "room" started, but have \[\"chat_1\"\]/) + }.to raise_error(/expected to have stream a string starting with "room" started, but have \["chat_1"\]/) end end end @@ -159,15 +159,15 @@ def subscribed subscribe user: 42 expect { - expect(subscription).to have_stream_for(StreamModel.new(31337)) - }.to raise_error(/expected to have stream "broadcast:StreamModel#31337" started, but have \[\"broadcast:StreamModel#42\"\]/) + expect(subscription).to have_stream_for(StreamModel.new(31_337)) + }.to raise_error(/expected to have stream "broadcast:StreamModel#31337" started, but have \["broadcast:StreamModel#42"\]/) end context "with negated form" do it "passes" do subscribe user: 42 - expect(subscription).not_to have_stream_for(StreamModel.new(31337)) + expect(subscription).not_to have_stream_for(StreamModel.new(31_337)) end it "fails with message" do @@ -175,7 +175,7 @@ def subscribed expect { expect(subscription).not_to have_stream_for(StreamModel.new(42)) - }.to raise_error(/expected not to have stream "broadcast:StreamModel#42" started, but have \[\"broadcast:StreamModel#42\"\]/) + }.to raise_error(/expected not to have stream "broadcast:StreamModel#42" started, but have \["broadcast:StreamModel#42"\]/) end end end diff --git a/spec/rspec/rails/matchers/active_job_spec.rb b/spec/rspec/rails/matchers/active_job_spec.rb index 02c3132016..9bec5fd33c 100644 --- a/spec/rspec/rails/matchers/active_job_spec.rb +++ b/spec/rspec/rails/matchers/active_job_spec.rb @@ -98,6 +98,43 @@ def self.name; "LoggingJob"; end expect { }.not_to have_enqueued_job end + context "when previously enqueued jobs were performed" do + include ActiveJob::TestHelper + + before { stub_const("HeavyLiftingJob", heavy_lifting_job) } + + it "counts newly enqueued jobs" do + heavy_lifting_job.perform_later + expect { + perform_enqueued_jobs + hello_job.perform_later + }.to have_enqueued_job(hello_job) + end + end + + context "when job is retried" do + include ActiveJob::TestHelper + + let(:unreliable_job) do + Class.new(ActiveJob::Base) do + retry_on StandardError, wait: 5, queue: :retry + + def self.name; "UnreliableJob"; end + def perform; raise StandardError; end + end + end + + before { stub_const("UnreliableJob", unreliable_job) } + + it "passes with reenqueued job" do + time = Time.current.change(usec: 0) + travel_to time do + UnreliableJob.perform_later + expect { perform_enqueued_jobs }.to have_enqueued_job(UnreliableJob).on_queue(:retry).at(time + 5) + end + end + end + it "fails when job is not enqueued" do expect { expect { }.to have_enqueued_job @@ -226,7 +263,7 @@ def self.name; "LoggingJob"; end end it "works with time offsets" do - # note that Time.current does not replicate Rails behavior for 5 seconds from now. + # NOTE: Time.current does not replicate Rails behavior for 5 seconds from now. time = Time.current.change(usec: 0) travel_to time do expect { hello_job.set(wait: 5).perform_later }.to have_enqueued_job.at(time + 5) @@ -347,14 +384,14 @@ def self.name; "LoggingJob"; end } end - it "passess deserialized arguments to with block" do + it "passes deserialized arguments to with block" do global_id_object = GlobalIdModel.new("42") expect { hello_job.perform_later(global_id_object, symbolized_key: "asdf") }.to have_enqueued_job(hello_job).with { |first_arg, second_arg| expect(first_arg).to eq(global_id_object) - expect(second_arg).to eq({symbolized_key: "asdf"}) + expect(second_arg).to eq({ symbolized_key: "asdf" }) } end @@ -379,22 +416,20 @@ def self.name; "LoggingJob"; end } end - if Rails.version.to_f >= 6.0 - it "passes with Time" do - usec_time = Time.iso8601('2016-07-01T00:00:00.000001Z') + it "passes with Time" do + usec_time = Time.iso8601('2016-07-01T00:00:00.000001Z') - expect { - hello_job.perform_later(usec_time) - }.to have_enqueued_job(hello_job).with(usec_time) - end + expect { + hello_job.perform_later(usec_time) + }.to have_enqueued_job(hello_job).with(usec_time) + end - it "passes with ActiveSupport::TimeWithZone" do - usec_time = Time.iso8601('2016-07-01T00:00:00.000001Z').in_time_zone + it "passes with ActiveSupport::TimeWithZone" do + usec_time = Time.iso8601('2016-07-01T00:00:00.000001Z').in_time_zone - expect { - hello_job.perform_later(usec_time) - }.to have_enqueued_job(hello_job).with(usec_time) - end + expect { + hello_job.perform_later(usec_time) + }.to have_enqueued_job(hello_job).with(usec_time) end end @@ -650,14 +685,14 @@ def self.name; "LoggingJob"; end } end - it "passess deserialized arguments to with block" do + it "passes deserialized arguments to with block" do global_id_object = GlobalIdModel.new("42") expect { hello_job.perform_later(global_id_object, symbolized_key: "asdf") }.to have_performed_job(hello_job).with { |first_arg, second_arg| expect(first_arg).to eq(global_id_object) - expect(second_arg).to eq({symbolized_key: "asdf"}) + expect(second_arg).to eq({ symbolized_key: "asdf" }) } end diff --git a/spec/rspec/rails/matchers/be_a_new_spec.rb b/spec/rspec/rails/matchers/be_a_new_spec.rb index b4e929ea8c..76906a56fc 100644 --- a/spec/rspec/rails/matchers/be_a_new_spec.rb +++ b/spec/rspec/rails/matchers/be_a_new_spec.rb @@ -81,7 +81,7 @@ def new_record?; true; end it "fails" do expect { expect(record).to be_a_new(record.class).with( - foo: a_hash_including({no_foo: "foo"})) + foo: a_hash_including({ no_foo: "foo" })) }.to raise_error { |e| expect(e.message).to eq("no implicit conversion of Hash into String").or eq("can't convert Hash into String") } diff --git a/spec/rspec/rails/matchers/be_routable_spec.rb b/spec/rspec/rails/matchers/be_routable_spec.rb index 81f27d37ca..c3a6a1b158 100644 --- a/spec/rspec/rails/matchers/be_routable_spec.rb +++ b/spec/rspec/rails/matchers/be_routable_spec.rb @@ -12,14 +12,14 @@ it "passes if routes recognize the path" do allow(routes).to receive(:recognize_path) { {} } expect do - expect({get: "/a/path"}).to be_routable + expect({ get: "/a/path" }).to be_routable end.to_not raise_error end it "fails if routes do not recognize the path" do - allow(routes).to receive(:recognize_path) { raise ActionController::RoutingError.new('ignore') } + allow(routes).to receive(:recognize_path) { raise ActionController::RoutingError, 'ignore' } expect do - expect({get: "/a/path"}).to be_routable + expect({ get: "/a/path" }).to be_routable end.to raise_error(/expected \{:get=>"\/a\/path"\} to be routable/) end end @@ -27,16 +27,16 @@ context "with should_not" do it "passes if routes do not recognize the path" do - allow(routes).to receive(:recognize_path) { raise ActionController::RoutingError.new('ignore') } + allow(routes).to receive(:recognize_path) { raise ActionController::RoutingError, 'ignore' } expect do - expect({get: "/a/path"}).not_to be_routable + expect({ get: "/a/path" }).not_to be_routable end.to_not raise_error end it "fails if routes recognize the path" do - allow(routes).to receive(:recognize_path) { {controller: "foo"} } + allow(routes).to receive(:recognize_path) { { controller: "foo" } } expect do - expect({get: "/a/path"}).not_to be_routable + expect({ get: "/a/path" }).not_to be_routable end.to raise_error(/expected \{:get=>"\/a\/path"\} not to be routable, but it routes to \{:controller=>"foo"\}/) end end diff --git a/spec/rspec/rails/matchers/be_valid_spec.rb b/spec/rspec/rails/matchers/be_valid_spec.rb index 2e3f1d11ed..c15f6e2d22 100644 --- a/spec/rspec/rails/matchers/be_valid_spec.rb +++ b/spec/rspec/rails/matchers/be_valid_spec.rb @@ -40,7 +40,7 @@ def errors(_) it "includes the error messages in the failure message" do expect { expect(post).to be_valid - }.to raise_exception(/Title can't be blank/) + }.to raise_exception(/Title can.t be blank/) end it "includes the error messages for simple implementations of error messages" do diff --git a/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb b/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb index 13bc1d1faf..bded88edc7 100644 --- a/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb +++ b/spec/rspec/rails/matchers/have_enqueued_mail_spec.rb @@ -386,7 +386,7 @@ def self.name; "NonMailerJob"; end expect { TestMailer.with('foo' => 'bar').email_with_args(1, 2).deliver_later - }.to have_enqueued_mail(TestMailer, :email_with_args).with({'foo' => 'bar'}, 1, 2) + }.to have_enqueued_mail(TestMailer, :email_with_args).with({ 'foo' => 'bar' }, 1, 2) end end @@ -414,17 +414,17 @@ def self.name; "NonMailerJob"; end expect { UnifiedMailer.with('foo' => 'bar').test_email.deliver_later }.to have_enqueued_mail(UnifiedMailer, :test_email).with( - a_hash_including(params: {'foo' => 'bar'}) + a_hash_including(params: { 'foo' => 'bar' }) ) expect { UnifiedMailer.with('foo' => 'bar').email_with_args(1, 2).deliver_later }.to have_enqueued_mail(UnifiedMailer, :email_with_args).with( - a_hash_including(params: {'foo' => 'bar'}, args: [1, 2]) + a_hash_including(params: { 'foo' => 'bar' }, args: [1, 2]) ) end - it "passes when given a global id serialised argument" do + it "passes when given a global id serialized argument" do expect { UnifiedMailer.with(inquiry: GlobalIDArgument.new).test_email.deliver_later }.to have_enqueued_email(UnifiedMailer, :test_email) diff --git a/spec/rspec/rails/matchers/have_rendered_spec.rb b/spec/rspec/rails/matchers/have_rendered_spec.rb index c665cc3f45..a45a9ba9b9 100644 --- a/spec/rspec/rails/matchers/have_rendered_spec.rb +++ b/spec/rspec/rails/matchers/have_rendered_spec.rb @@ -6,8 +6,8 @@ context "given a hash" do def assert_template(*); end it "delegates to assert_template" do - expect(self).to receive(:assert_template).with({this: "hash"}, "this message") - expect("response").to send(template_expectation, {this: "hash"}, "this message") + expect(self).to receive(:assert_template).with({ this: "hash" }, "this message") + expect("response").to send(template_expectation, { this: "hash" }, "this message") end end @@ -40,7 +40,7 @@ def assert_template(*); end context "when assert_template fails" do it "uses failure message from assert_template" do def assert_template(*) - raise ActiveSupport::TestCase::Assertion.new("this message") + raise ActiveSupport::TestCase::Assertion, "this message" end expect do expect(response).to send(template_expectation, "template_name") @@ -64,7 +64,7 @@ def assert_template(*) context "when assert_template fails" do it "passes" do def assert_template(*) - raise ActiveSupport::TestCase::Assertion.new("this message") + raise ActiveSupport::TestCase::Assertion, "this message" end expect do expect(response).to_not send(template_expectation, "template_name") @@ -77,7 +77,7 @@ def assert_template(*) def assert_template(*); end expect do expect(response).to_not send(template_expectation, "template_name") - end.to raise_error(/expected not to render \"template_name\", but did/) + end.to raise_error(/expected not to render "template_name", but did/) end end @@ -95,7 +95,7 @@ def assert_template(*); raise "oops"; end def assert_template(*) message = "expecting <'template_name'> but rendering with <[]>" - raise ActiveSupport::TestCase::Assertion.new(message) + raise ActiveSupport::TestCase::Assertion, message end def normalize_argument_to_redirection(_response_redirect_location) @@ -113,7 +113,7 @@ def normalize_argument_to_redirection(_response_redirect_location) context 'with a badly formatted error message' do def assert_template(*) message = 'expected [] to include "some/path"' - raise ActiveSupport::TestCase::Assertion.new(message) + raise ActiveSupport::TestCase::Assertion, message end it 'falls back to something informative' do diff --git a/spec/rspec/rails/matchers/redirect_to_spec.rb b/spec/rspec/rails/matchers/redirect_to_spec.rb index dbced18f2e..462531bcc9 100644 --- a/spec/rspec/rails/matchers/redirect_to_spec.rb +++ b/spec/rspec/rails/matchers/redirect_to_spec.rb @@ -19,7 +19,7 @@ def assert_redirected_to(*); end context "when assert_redirected_to fails" do def assert_redirected_to(*) - raise ActiveSupport::TestCase::Assertion.new("this message") + raise ActiveSupport::TestCase::Assertion, "this message" end it "uses failure message from assert_redirected_to" do @@ -45,7 +45,7 @@ def assert_redirected_to(*) context "with should_not" do context "when assert_redirected_to fails" do def assert_redirected_to(*) - raise ActiveSupport::TestCase::Assertion.new("this message") + raise ActiveSupport::TestCase::Assertion, "this message" end it "passes" do @@ -61,7 +61,7 @@ def assert_redirected_to(*); end it "fails with custom failure message" do expect do expect(response).not_to redirect_to("destination") - end.to raise_exception(/expected not to redirect to \"destination\", but did/) + end.to raise_exception(/expected not to redirect to "destination", but did/) end end diff --git a/spec/rspec/rails/matchers/route_to_spec.rb b/spec/rspec/rails/matchers/route_to_spec.rb index 5c32918e5b..ae49791f8a 100644 --- a/spec/rspec/rails/matchers/route_to_spec.rb +++ b/spec/rspec/rails/matchers/route_to_spec.rb @@ -13,20 +13,20 @@ def assert_recognizes(*) end it "delegates to assert_recognizes" do - expect(self).to receive(:assert_recognizes).with({"these" => "options"}, {method: :get, path: "path"}, {}) - expect({get: "path"}).to route_to("these" => "options") + expect(self).to receive(:assert_recognizes).with({ "these" => "options" }, { method: :get, path: "path" }, {}) + expect({ get: "path" }).to route_to("these" => "options") end context "with shortcut syntax" do it "routes with extra options" do - expect(self).to receive(:assert_recognizes).with({controller: "controller", action: "action", extra: "options"}, {method: :get, path: "path"}, {}) + expect(self).to receive(:assert_recognizes).with({ controller: "controller", action: "action", extra: "options" }, { method: :get, path: "path" }, {}) expect(get("path")).to route_to("controller#action", extra: "options") end it "routes without extra options" do expect(self).to receive(:assert_recognizes).with( - {controller: "controller", action: "action"}, - {method: :get, path: "path"}, + { controller: "controller", action: "action" }, + { method: :get, path: "path" }, {} ) expect(get("path")).to route_to("controller#action") @@ -34,29 +34,29 @@ def assert_recognizes(*) it "routes with one query parameter" do expect(self).to receive(:assert_recognizes).with( - {controller: "controller", action: "action", queryitem: "queryvalue"}, - {method: :get, path: "path"}, - {'queryitem' => 'queryvalue'} + { controller: "controller", action: "action", queryitem: "queryvalue" }, + { method: :get, path: "path" }, + { 'queryitem' => 'queryvalue' } ) expect(get("path?queryitem=queryvalue")).to route_to("controller#action", queryitem: 'queryvalue') end it "routes with multiple query parameters" do expect(self).to receive(:assert_recognizes).with( - {controller: "controller", action: "action", queryitem: "queryvalue", qi2: 'qv2'}, - {method: :get, path: "path"}, - {'queryitem' => 'queryvalue', 'qi2' => 'qv2'} + { controller: "controller", action: "action", queryitem: "queryvalue", qi2: 'qv2' }, + { method: :get, path: "path" }, + { 'queryitem' => 'queryvalue', 'qi2' => 'qv2' } ) expect(get("path?queryitem=queryvalue&qi2=qv2")).to route_to("controller#action", queryitem: 'queryvalue', qi2: 'qv2') end it "routes with nested query parameters" do expect(self).to receive(:assert_recognizes).with( - {:controller => "controller", :action => "action", 'queryitem' => {'qi2' => 'qv2'}}, - {method: :get, path: "path"}, - {'queryitem' => {'qi2' => 'qv2'}} + { :controller => "controller", :action => "action", 'queryitem' => { 'qi2' => 'qv2' } }, + { method: :get, path: "path" }, + { 'queryitem' => { 'qi2' => 'qv2' } } ) - expect(get("path?queryitem[qi2]=qv2")).to route_to("controller#action", 'queryitem' => {'qi2' => 'qv2'}) + expect(get("path?queryitem[qi2]=qv2")).to route_to("controller#action", 'queryitem' => { 'qi2' => 'qv2' }) end end @@ -65,7 +65,7 @@ def assert_recognizes(*) context "when assert_recognizes passes" do it "passes" do expect do - expect({get: "path"}).to route_to("these" => "options") + expect({ get: "path" }).to route_to("these" => "options") end.to_not raise_exception end end @@ -73,10 +73,10 @@ def assert_recognizes(*) context "when assert_recognizes fails with an assertion failure" do it "fails with message from assert_recognizes" do def assert_recognizes(*) - raise ActiveSupport::TestCase::Assertion.new("this message") + raise ActiveSupport::TestCase::Assertion, "this message" end expect do - expect({get: "path"}).to route_to("these" => "options") + expect({ get: "path" }).to route_to("these" => "options") end.to raise_error(RSpec::Expectations::ExpectationNotMetError, "this message") end end @@ -84,10 +84,10 @@ def assert_recognizes(*) context "when assert_recognizes fails with a routing error" do it "fails with message from assert_recognizes" do def assert_recognizes(*) - raise ActionController::RoutingError.new("this message") + raise ActionController::RoutingError, "this message" end expect do - expect({get: "path"}).to route_to("these" => "options") + expect({ get: "path" }).to route_to("these" => "options") end.to raise_error(RSpec::Expectations::ExpectationNotMetError, "this message") end end @@ -98,7 +98,7 @@ def assert_recognizes(*) raise "oops" end expect do - expect({get: "path"}).to route_to("these" => "options") + expect({ get: "path" }).to route_to("these" => "options") end.to raise_exception("oops") end end @@ -108,7 +108,7 @@ def assert_recognizes(*) context "when assert_recognizes passes" do it "fails with custom message" do expect { - expect({get: "path"}).not_to route_to("these" => "options") + expect({ get: "path" }).not_to route_to("these" => "options") }.to raise_error(/expected \{:get=>"path"\} not to route to \{"these"=>"options"\}/) end end @@ -116,10 +116,10 @@ def assert_recognizes(*) context "when assert_recognizes fails with an assertion failure" do it "passes" do def assert_recognizes(*) - raise ActiveSupport::TestCase::Assertion.new("this message") + raise ActiveSupport::TestCase::Assertion, "this message" end expect do - expect({get: "path"}).not_to route_to("these" => "options") + expect({ get: "path" }).not_to route_to("these" => "options") end.to_not raise_error end end @@ -127,10 +127,10 @@ def assert_recognizes(*) context "when assert_recognizes fails with a routing error" do it "passes" do def assert_recognizes(*) - raise ActionController::RoutingError.new("this message") + raise ActionController::RoutingError, "this message" end expect do - expect({get: "path"}).not_to route_to("these" => "options") + expect({ get: "path" }).not_to route_to("these" => "options") end.to_not raise_error end end @@ -141,7 +141,7 @@ def assert_recognizes(*) raise "oops" end expect do - expect({get: "path"}).not_to route_to("these" => "options") + expect({ get: "path" }).not_to route_to("these" => "options") end.to raise_exception("oops") end end @@ -152,7 +152,7 @@ def assert_recognizes(*) raise ActiveSupport::TestCase::Assertion, "this message" end expect do - expect({"this" => "path"}).to route_to("these" => "options") + expect({ "this" => "path" }).to route_to("these" => "options") end.to raise_error("this message") end end diff --git a/spec/rspec/rails/view_rendering_spec.rb b/spec/rspec/rails/view_rendering_spec.rb index 4eedba2b11..3273f20154 100644 --- a/spec/rspec/rails/view_rendering_spec.rb +++ b/spec/rspec/rails/view_rendering_spec.rb @@ -60,7 +60,7 @@ def example.controller end end - it 'propogates to examples in nested groups properly' do + it 'propagates to examples in nested groups properly' do value = :unset group.class_exec do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6d3c5a3f64..0f020214b9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,7 @@ class Application < ::Rails::Application config.secret_key_base = 'ASecretString' if defined?(ActionCable) - ActionCable.server.config.cable = {"adapter" => "test"} + ActionCable.server.config.cable = { "adapter" => "test" } ActionCable.server.config.logger = ActiveSupport::TaggedLogging.new ActiveSupport::Logger.new(StringIO.new) end diff --git a/spec/support/generators.rb b/spec/support/generators.rb index 9081b054dc..f57dc2b885 100644 --- a/spec/support/generators.rb +++ b/spec/support/generators.rb @@ -73,7 +73,7 @@ def self.included(klass) it "the generator describes the provided NAME without monkey " \ "patching setting the type to `:request`" do expect(request_spec).to contain( - /^RSpec.describe \"Posts\", #{type_metatag(:request)}/ + /^RSpec.describe "Posts", #{type_metatag(:request)}/ ) end @@ -101,12 +101,12 @@ def self.included(klass) it "the generator describes the provided NAME without monkey " \ "patching setting the type to `:request`" do expect(request_spec).to contain( - /^RSpec.describe \"Api::Posts\", #{type_metatag(:request)}/ + /^RSpec.describe "Api::Posts", #{type_metatag(:request)}/ ) end it "the generator includes a sample GET request" do - expect(request_spec).to contain(/describe "GET \/api\/posts\"/) + expect(request_spec).to contain(/describe "GET \/api\/posts"/) end it "the generator sends the GET request to the index path" do diff --git a/spec/support/shared_examples.rb b/spec/support/shared_examples.rb index 510bc4fbc2..12f8850d41 100644 --- a/spec/support/shared_examples.rb +++ b/spec/support/shared_examples.rb @@ -43,18 +43,18 @@ def define_group_in(path, group_definition) expect(group.included_modules).to include(mixin) end - it "tags groups in that directory with `:type => #{type.inspect}`" do + it "tags groups in that directory with `type: #{type.inspect}`" do group = define_group_in path, "RSpec.describe" expect(group.metadata).to include(type: type) end it "allows users to override the type" do - group = define_group_in path, "RSpec.describe 'group', :type => :other" + group = define_group_in path, "RSpec.describe 'group', type: :other" expect(group.metadata).to include(type: :other) expect(group.included_modules).not_to include(mixin) end - it "applies configured `before(:context)` hooks with `:type => #{type.inspect}` metadata" do + it "applies configured `before(:context)` hooks with `type: #{type.inspect}` metadata" do block_run = false RSpec.configuration.before(:context, type: type) { block_run = true } @@ -66,15 +66,15 @@ def define_group_in(path, group_definition) end end - it "includes itself in example groups tagged with `:type => #{type.inspect}`" do - group = define_group_in "spec/other", "RSpec.describe 'group', :type => #{type.inspect}" + it "includes itself in example groups tagged with `type: #{type.inspect}`" do + group = define_group_in "spec/other", "RSpec.describe 'group', type: #{type.inspect}" expect(group.included_modules).to include(mixin) end end context 'when `infer_spec_type_from_file_location!` is not configured' do - it "includes itself in example groups tagged with `:type => #{type.inspect}`" do - group = define_group_in "spec/other", "RSpec.describe 'group', :type => #{type.inspect}" + it "includes itself in example groups tagged with `type: #{type.inspect}`" do + group = define_group_in "spec/other", "RSpec.describe 'group', type: #{type.inspect}" expect(group.included_modules).to include(mixin) end @@ -85,7 +85,7 @@ def define_group_in(path, group_definition) expect(group.included_modules).not_to include(mixin) end - it "does not tag groups in that directory with `:type => #{type.inspect}`" do + it "does not tag groups in that directory with `type: #{type.inspect}`" do group = define_group_in path, "RSpec.describe" expect(group.metadata).not_to include(:type) end