├── .git-hooks └── pre_push │ └── rubocop.rb ├── .github └── workflows │ ├── test_and_publish.yml │ ├── test_only.yml │ └── verify_version_change.yml ├── .gitignore ├── .overcommit.yml ├── .prettierrc.js ├── .rspec ├── .rubocop-http---relaxed-ruby-style-rubocop-yml ├── .rubocop.yml ├── .ruby-gemset ├── .ruby-version ├── CHANGELOG.md ├── Gemfile ├── Guardfile ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── lib ├── rspec_in_context.rb └── rspec_in_context │ ├── context_management.rb │ ├── in_context.rb │ └── version.rb ├── package.json ├── rspec_in_context.gemspec ├── spec ├── rspec_in_context │ ├── context_management_spec.rb │ └── in_context_spec.rb ├── spec_helper.rb └── support │ └── context_test_helper.rb └── yarn.lock /.git-hooks/pre_push/rubocop.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Overcommit 4 | module Hook 5 | module PrePush 6 | # Runs `rubocop` on every files. 7 | class Rubocop < Base 8 | def run 9 | result = execute(%w[rubocop -P]) 10 | return :pass if result.success? 11 | 12 | output = result.stdout + result.stderr 13 | [:fail, output] 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /.github/workflows/test_and_publish.yml: -------------------------------------------------------------------------------- 1 | name: Test and Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | tests: 10 | strategy: 11 | matrix: 12 | ruby: [2.5, 2.6, 2.7, 3.0] 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Ruby 18 | uses: ruby/setup-ruby@v1 19 | with: 20 | ruby-version: ${{ matrix.ruby }} 21 | bundler-cache: true 22 | - name: Run linter 23 | run: bundle exec rubocop 24 | - name: Run tests 25 | run: bundle exec rspec 26 | prettier: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v2 30 | - name: Set up Node 31 | uses: actions/setup-node@v2 32 | with: 33 | node-version: '14' 34 | - name: Install yarn dep 35 | run: yarn install 36 | - name: Check prettier 37 | run: yarn prettier -c '**/*.rb' 38 | release: 39 | needs: [tests, prettier] 40 | runs-on: ubuntu-latest 41 | 42 | steps: 43 | - uses: actions/checkout@v2 44 | - name: Set up Ruby 45 | uses: ruby/setup-ruby@v1 46 | with: 47 | ruby-version: 3.0 48 | bundler-cache: true 49 | - name: Prepare credentials 50 | env: 51 | RUBYGEM_KEY: ${{ secrets.RUBYGEM_KEY }} 52 | run: "mkdir -p ~/.gem && echo -e \"---\\r\\n:rubygems_api_key: $RUBYGEM_KEY\" > ~/.gem/credentials && chmod 0600 ~/.gem/credentials" 53 | - name: Setup username/email 54 | run: "git config --global user.email zaratan@hey.com && git config --global user.name \"Denis Pasin\"" 55 | - name: Fetch tags from remote 56 | run: "git fetch -t" 57 | - name: Publish if version change 58 | run: 'git diff `git tag | tail -1` -- lib/rspec_in_context/version.rb | grep -E "^\+.*VERSION" && rake release || echo "No release for now"' 59 | -------------------------------------------------------------------------------- /.github/workflows/test_only.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - main 7 | 8 | jobs: 9 | tests: 10 | strategy: 11 | matrix: 12 | ruby: [2.5, 2.6, 2.7, 3.0] 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Ruby 18 | uses: ruby/setup-ruby@v1 19 | with: 20 | ruby-version: ${{ matrix.ruby }} 21 | bundler-cache: true 22 | - name: Run linter 23 | run: bundle exec rubocop 24 | - name: Run tests 25 | run: bundle exec rspec 26 | prettier: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v2 30 | - name: Set up Node 31 | uses: actions/setup-node@v2 32 | with: 33 | node-version: '14' 34 | - name: Install yarn dep 35 | run: yarn install 36 | - name: Check prettier 37 | run: yarn prettier -c '**/*.rb' 38 | -------------------------------------------------------------------------------- /.github/workflows/verify_version_change.yml: -------------------------------------------------------------------------------- 1 | name: Verify version change 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | version_change: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Fetch main branch 15 | run: git fetch origin main:main 16 | - name: Verify if there's a change in version 17 | run: "git diff main -- lib/rspec_in_context/version.rb | grep VERSION" 18 | - name: Print new version 19 | run: 'git diff main -- lib/rspec_in_context/version.rb | grep -E "^\+.*VERSION" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?"' 20 | - name: Verify if higher version 21 | run: '[[ $(git diff main -- lib/rspec_in_context/version.rb | grep -E "^\+.*VERSION" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?") > $(git diff main -- lib/rspec_in_context/version.rb | grep -E "^-.*VERSION" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?") ]]' 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | 10 | Gemfile.lock 11 | vendor/cache 12 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | PreCommit: 2 | RuboCop: 3 | enabled: true 4 | command: ['bundle', 'exec', 'rubocop', '-P'] # Invoke within Bundler context 5 | BundleOutdated: 6 | enabled: true 7 | BundleAudit: 8 | enabled: true 9 | PrePush: 10 | RSpec: 11 | enabled: true 12 | command: ['bundle', 'exec', 'rspec'] # Invoke within Bundler context 13 | Rubocop: 14 | enabled: true 15 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: "es5", 3 | singleQuote: true, 4 | printWidth: 120, 5 | }; 6 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | -------------------------------------------------------------------------------- /.rubocop-http---relaxed-ruby-style-rubocop-yml: -------------------------------------------------------------------------------- 1 | # Relaxed.Ruby.Style 2 | ## Version 2.5 3 | 4 | Style/Alias: 5 | Enabled: false 6 | StyleGuide: https://relaxed.ruby.style/#stylealias 7 | 8 | Style/AsciiComments: 9 | Enabled: false 10 | StyleGuide: https://relaxed.ruby.style/#styleasciicomments 11 | 12 | Style/BeginBlock: 13 | Enabled: false 14 | StyleGuide: https://relaxed.ruby.style/#stylebeginblock 15 | 16 | Style/BlockDelimiters: 17 | Enabled: false 18 | StyleGuide: https://relaxed.ruby.style/#styleblockdelimiters 19 | 20 | Style/CommentAnnotation: 21 | Enabled: false 22 | StyleGuide: https://relaxed.ruby.style/#stylecommentannotation 23 | 24 | Style/Documentation: 25 | Enabled: false 26 | StyleGuide: https://relaxed.ruby.style/#styledocumentation 27 | 28 | Layout/DotPosition: 29 | Enabled: false 30 | StyleGuide: https://relaxed.ruby.style/#layoutdotposition 31 | 32 | Style/DoubleNegation: 33 | Enabled: false 34 | StyleGuide: https://relaxed.ruby.style/#styledoublenegation 35 | 36 | Style/EndBlock: 37 | Enabled: false 38 | StyleGuide: https://relaxed.ruby.style/#styleendblock 39 | 40 | Style/FormatString: 41 | Enabled: false 42 | StyleGuide: https://relaxed.ruby.style/#styleformatstring 43 | 44 | Style/IfUnlessModifier: 45 | Enabled: false 46 | StyleGuide: https://relaxed.ruby.style/#styleifunlessmodifier 47 | 48 | Style/Lambda: 49 | Enabled: false 50 | StyleGuide: https://relaxed.ruby.style/#stylelambda 51 | 52 | Style/ModuleFunction: 53 | Enabled: false 54 | StyleGuide: https://relaxed.ruby.style/#stylemodulefunction 55 | 56 | Style/MultilineBlockChain: 57 | Enabled: false 58 | StyleGuide: https://relaxed.ruby.style/#stylemultilineblockchain 59 | 60 | Style/NegatedIf: 61 | Enabled: false 62 | StyleGuide: https://relaxed.ruby.style/#stylenegatedif 63 | 64 | Style/NegatedWhile: 65 | Enabled: false 66 | StyleGuide: https://relaxed.ruby.style/#stylenegatedwhile 67 | 68 | Style/NumericPredicate: 69 | Enabled: false 70 | StyleGuide: https://relaxed.ruby.style/#stylenumericpredicate 71 | 72 | Style/ParallelAssignment: 73 | Enabled: false 74 | StyleGuide: https://relaxed.ruby.style/#styleparallelassignment 75 | 76 | Style/PercentLiteralDelimiters: 77 | Enabled: false 78 | StyleGuide: https://relaxed.ruby.style/#stylepercentliteraldelimiters 79 | 80 | Style/PerlBackrefs: 81 | Enabled: false 82 | StyleGuide: https://relaxed.ruby.style/#styleperlbackrefs 83 | 84 | Style/Semicolon: 85 | Enabled: false 86 | StyleGuide: https://relaxed.ruby.style/#stylesemicolon 87 | 88 | Style/SignalException: 89 | Enabled: false 90 | StyleGuide: https://relaxed.ruby.style/#stylesignalexception 91 | 92 | Style/SingleLineBlockParams: 93 | Enabled: false 94 | StyleGuide: https://relaxed.ruby.style/#stylesinglelineblockparams 95 | 96 | Style/SingleLineMethods: 97 | Enabled: false 98 | StyleGuide: https://relaxed.ruby.style/#stylesinglelinemethods 99 | 100 | Layout/SpaceBeforeBlockBraces: 101 | Enabled: false 102 | StyleGuide: https://relaxed.ruby.style/#layoutspacebeforeblockbraces 103 | 104 | Layout/SpaceInsideParens: 105 | Enabled: false 106 | StyleGuide: https://relaxed.ruby.style/#layoutspaceinsideparens 107 | 108 | Style/SpecialGlobalVars: 109 | Enabled: false 110 | StyleGuide: https://relaxed.ruby.style/#stylespecialglobalvars 111 | 112 | Style/StringLiterals: 113 | Enabled: false 114 | StyleGuide: https://relaxed.ruby.style/#stylestringliterals 115 | 116 | Style/TrailingCommaInArguments: 117 | Enabled: false 118 | StyleGuide: https://relaxed.ruby.style/#styletrailingcommainarguments 119 | 120 | Style/TrailingCommaInArrayLiteral: 121 | Enabled: false 122 | StyleGuide: https://relaxed.ruby.style/#styletrailingcommainarrayliteral 123 | 124 | Style/TrailingCommaInHashLiteral: 125 | Enabled: false 126 | StyleGuide: https://relaxed.ruby.style/#styletrailingcommainhashliteral 127 | 128 | Style/SymbolArray: 129 | Enabled: false 130 | StyleGuide: http://relaxed.ruby.style/#stylesymbolarray 131 | 132 | Style/WhileUntilModifier: 133 | Enabled: false 134 | StyleGuide: https://relaxed.ruby.style/#stylewhileuntilmodifier 135 | 136 | Style/WordArray: 137 | Enabled: false 138 | StyleGuide: https://relaxed.ruby.style/#stylewordarray 139 | 140 | Lint/AmbiguousRegexpLiteral: 141 | Enabled: false 142 | StyleGuide: https://relaxed.ruby.style/#lintambiguousregexpliteral 143 | 144 | Lint/AssignmentInCondition: 145 | Enabled: false 146 | StyleGuide: https://relaxed.ruby.style/#lintassignmentincondition 147 | 148 | Layout/LineLength: 149 | Enabled: false 150 | 151 | Metrics: 152 | Enabled: false 153 | 154 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: 2 | - http://relaxed.ruby.style/rubocop.yml 3 | 4 | inherit_gem: 5 | prettier: rubocop.yml 6 | 7 | require: 8 | - rubocop-performance 9 | 10 | AllCops: 11 | NewCops: enable 12 | DisplayStyleGuide: true 13 | DisplayCopNames: true 14 | SuggestExtensions: false 15 | Exclude: 16 | - 'bin/*' 17 | - 'vendor/**/*' 18 | - 'node_modules/**/*' 19 | 20 | Metrics/BlockLength: 21 | Exclude: 22 | - 'spec/**/*.rb' 23 | - 'Guardfile' 24 | - 'vendor/bundle' 25 | - '*.gemspec' 26 | 27 | Lint/EmptyBlock: 28 | Enabled: false 29 | 30 | Style/GlobalVars: 31 | Exclude: 32 | - spec/rspec_in_context/in_context_spec.rb 33 | 34 | ### Prettier 35 | Style/OptionalBooleanParameter: 36 | Enabled: false 37 | 38 | Style/GuardClause: 39 | Enabled: false 40 | 41 | ### End Prettier 42 | Naming/MethodParameterName: 43 | Enabled: false 44 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | rspec_in_context 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.0.0 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [1.1.0.3] - 2021-01-13 10 | ### Added 11 | - Reformating code with Prettier-ruby 12 | 13 | ## [1.1.0.2] - 2021-01-08 14 | ### Changed 15 | - Wrapping silent in_context in anonymous contexts 16 | 17 | ## [1.1.0.1] - 2020-12-27 18 | This is a release in order to test all type of actions 19 | 20 | ### Added 21 | - Cache support in github actions for ease of development 22 | 23 | 24 | ## [1.1.0] - 2020-12-27 25 | ### Added 26 | - **BREAKING** Option to silence in_context block. They used to always wrap themself into a context block with their name. This is not the case anymore. All in_context are silent unless explicitely declared as not. 27 | 28 | ## [1.0.1.2] - 2020-12-26 29 | ### Added 30 | - Changelog 31 | - Support ruby 3.0 32 | 33 | [Unreleased]: https://github.com/zaratan/rspec_in_context/compare/v1.1.0.1...HEAD 34 | [1.1.0.1]: https://github.com/zaratan/rspec_in_context/releases/tag/v1.1.0.1 35 | [1.1.0]: https://github.com/zaratan/rspec_in_context/releases/tag/v1.1.0 36 | [1.0.1.2]: https://github.com/zaratan/rspec_in_context/releases/tag/v1.0.1.2 37 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } 6 | 7 | # Specify your gem's dependencies in rspec_in_context.gemspec 8 | gemspec 9 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # A sample Guardfile 4 | # More info at https://github.com/guard/guard#readme 5 | 6 | ## Uncomment and set this to only include directories you want to watch 7 | # directories %w(app lib config test spec features) \ 8 | # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")} 9 | 10 | ## Note: if you are using the `directories` clause above and you are not 11 | ## watching the project directory ('.'), then you will want to move 12 | ## the Guardfile to a watched dir and symlink it back, e.g. 13 | # 14 | # $ mkdir config 15 | # $ mv Guardfile config/ 16 | # $ ln -s config/Guardfile . 17 | # 18 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile" 19 | 20 | # Note: The cmd option is now required due to the increasing number of ways 21 | # rspec may be run, below are examples of the most common uses. 22 | # * bundler: 'bundle exec rspec' 23 | # * bundler binstubs: 'bin/rspec' 24 | # * spring: 'bin/rspec' (This will use spring if running and you have 25 | # installed the spring binstubs per the docs) 26 | # * zeus: 'zeus rspec' (requires the server to be started separately) 27 | # * 'just' rspec: 'rspec' 28 | 29 | guard :rspec, cmd: "bundle exec rspec" do 30 | require "guard/rspec/dsl" 31 | dsl = Guard::RSpec::Dsl.new(self) 32 | 33 | # Feel free to open issues for suggestions and improvements 34 | 35 | # RSpec files 36 | rspec = dsl.rspec 37 | watch(rspec.spec_helper) { rspec.spec_dir } 38 | watch(rspec.spec_support) { rspec.spec_dir } 39 | watch(rspec.spec_files) 40 | 41 | # map lib files to corresponding file 42 | watch(%r{lib/(.*)/([^/]*).rb}) { |m| rspec.spec.call("#{m[1]}/#{m[2]}") } 43 | 44 | # Ruby files 45 | ruby = dsl.ruby 46 | dsl.watch_spec_files_for(ruby.lib_files) 47 | end 48 | 49 | guard :rubocop do 50 | watch(/.+\.rb$/) 51 | watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) } 52 | end 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RspecInContext 2 | 3 | [![Gem Version](https://badge.fury.io/rb/rspec_in_context.svg)](https://badge.fury.io/rb/rspec_in_context) 4 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6490834b08664dc898d0107c74a78357)](https://www.codacy.com/gh/zaratan/rspec_in_context/dashboard?utm_source=github.com&utm_medium=referral&utm_content=zaratan/rspec_in_context&utm_campaign=Badge_Grade) 5 | ![Test and Release badge](https://github.com/zaratan/rspec_in_context/workflows/Test%20and%20Release/badge.svg) 6 | 7 | This gem is here to help you write better shared_examples in Rspec. 8 | 9 | Ever been bothered by the fact that they don't really behave like methods and that you can't pass it a block ? There you go: `rspec_in_context` 10 | 11 | ## Installation 12 | 13 | Add this line to your application's Gemfile: 14 | 15 | ```ruby 16 | gem 'rspec_in_context' 17 | ``` 18 | 19 | And then execute: 20 | 21 | $ bundle 22 | 23 | Or install it yourself as: 24 | 25 | $ gem install rspec_in_context 26 | 27 | ## Usage 28 | 29 | ### Add this into Rspec 30 | 31 | You must require the gem on top of your spec_helper: 32 | ```ruby 33 | require 'rspec_in_context' 34 | ``` 35 | 36 | Then include it into Rspec: 37 | ```ruby 38 | RSpec.configure do |config| 39 | [...] 40 | 41 | config.include RspecInContext 42 | end 43 | ``` 44 | 45 | ### Define a new in_context 46 | 47 | You can define in_context block that are reusable almost anywhere. 48 | They completely look like normal Rspec. 49 | 50 | ##### Inside a Rspec block (scoped) 51 | 52 | ```ruby 53 | # A in_context can be named with a symbol or a string 54 | define_context :context_name do 55 | it 'works' do 56 | expect(true).to be_truthy 57 | end 58 | end 59 | ``` 60 | 61 | Those in_context will be scoped to their current `describe`/`context` block. 62 | 63 | ##### Outside a Rspec block (globally) 64 | 65 | Outside of a test you have to use `RSpec.define_context`. Those in_context will be defined globally in your tests. 66 | 67 | 68 | ### Use the context 69 | 70 | Anywhere in your test description, use a `in_context` block to use a predefined in_context. 71 | 72 | **Important**: in_context are scoped to their current `describe`/`context` block. If you need globally defined context see `RSpec.define_context` 73 | 74 | ```ruby 75 | # A in_context can be named with a symbol or a string 76 | RSpec.define_context :context_name do 77 | it 'works' do 78 | expect(true).to be_truthy 79 | end 80 | end 81 | 82 | [...] 83 | Rspec.describe MyClass do 84 | in_context :context_name # => will execute the 'it works' test here 85 | end 86 | ``` 87 | 88 | ### Things to know 89 | 90 | #### Inside block execution 91 | 92 | * You can chose exactly where your inside test will be used: 93 | By using `execute_tests` in your define context, the test passed when you *use* the context will be executed here 94 | 95 | ```ruby 96 | define_context :context_name do 97 | it 'works' do 98 | expect(true).to be_truthy 99 | end 100 | context "in this context pomme exists" do 101 | let(:pomme) { "abcd" } 102 | 103 | execute_tests 104 | end 105 | end 106 | 107 | [...] 108 | 109 | in_context :context_name do 110 | it 'will be executed at execute_tests place' do 111 | expect(pomme).to eq("abcd") # => true 112 | end 113 | end 114 | ``` 115 | 116 | * You can add variable instantiation relative to your test where you exactly want: 117 | 118 | `instanciate_context` is an alias of `execute_tests` so you can't use both. 119 | But it let you describe what the block will do better. 120 | 121 | #### Variable usage 122 | 123 | * You can use variable in the in_context definition 124 | 125 | ```ruby 126 | define_context :context_name do |name| 127 | it 'works' do 128 | expect(true).to be_truthy 129 | end 130 | context "in this context #{name} exists" do 131 | let(name) { "abcd" } 132 | 133 | execute_tests 134 | end 135 | end 136 | 137 | [...] 138 | 139 | in_context :context_name, :poire do 140 | it 'the right variable will exists' do 141 | expect(poire).to eq("abcd") # => true 142 | end 143 | end 144 | ``` 145 | 146 | #### Scoping 147 | 148 | * In_contexts can be scope inside one another 149 | 150 | ```ruby 151 | define_context :context_name do |name| 152 | it 'works' do 153 | expect(true).to be_truthy 154 | end 155 | context "in this context #{name} exists" do 156 | let(name) { "abcd" } 157 | 158 | execute_tests 159 | end 160 | end 161 | 162 | define_context "second in_context" do 163 | context 'and tree also' do 164 | let(:tree) { 'abcd' } 165 | 166 | it 'will scope correctly' do 167 | expect(tree).to eq(poire) 168 | end 169 | end 170 | end 171 | 172 | [...] 173 | 174 | in_context :context_name, :poire do 175 | it 'the right variable will exists' do 176 | expect(poire).to eq("abcd") # => true 177 | end 178 | 179 | in_context "second in_context" # => will work 180 | end 181 | ``` 182 | 183 | * in_context are bound to their current scope 184 | 185 | #### Namespacing 186 | 187 | * You can add a namespace to a in_context definition 188 | 189 | ```ruby 190 | define_context "this is a namespaced context", namespace: "namespace name" 191 | ``` 192 | Or 193 | ```ruby 194 | define_context "this is a namespaced context", ns: "namespace name" 195 | ``` 196 | Or 197 | ```ruby 198 | RSpec.define_context "this is a namespaced context", ns: "namespace name" 199 | ``` 200 | 201 | * When you want to use a namespaced in_context, you have two choice: 202 | 203 | Ignore any namespace and it will try to find a corresponding in_context in any_namespace (the ones defined without namespace have the priority); 204 | ```ruby 205 | define_context "namespaced context", ns: "namespace name" do 206 | [...] 207 | end 208 | 209 | in_context "namespaced context" 210 | ``` 211 | 212 | Pass a namespace and it will look only in this context. 213 | ```ruby 214 | define_context "namespaced context", ns: "namespace name" do 215 | [...] 216 | end 217 | 218 | in_context "namespaced context", namespace: "namespace name" 219 | in_context "namespaced context", ns: "namespace name" 220 | ``` 221 | 222 | #### Making `in_context` adverstise itself 223 | 224 | The fact that a `in_context` block is used inside the test is silent and invisible by default. 225 | `in_context` will still wrap its own execution inside a anonymous context. 226 | 227 | But, there's some case where it helps to make the `in_context` to wrap its execution in a named `context` block. 228 | For example: 229 | ```ruby 230 | define_context "with my_var defined" do 231 | before do 232 | described_class.set_my_var(true) 233 | end 234 | 235 | it "works" 236 | end 237 | 238 | define_context "without my_var defined" do 239 | it "doesn't work" 240 | end 241 | 242 | RSpec.describe MyNiceClass do 243 | in_context "with my_var defined" 244 | in_context "without my_var defined" 245 | end 246 | ``` 247 | Using a `rspec -f doc` will only print "MyNiceClass works" and "MyNiceClass doesn't work" which is not really a good documentation. 248 | 249 | So, you can define a context specifying it not to be `silent` or to `print_context`. 250 | For example : 251 | ```ruby 252 | define_context "with my_var defined", silent: false do 253 | before do 254 | described_class.set_my_var(true) 255 | end 256 | 257 | it "works" 258 | end 259 | 260 | define_context "without my_var defined", print_context: true do 261 | it "doesn't work" 262 | end 263 | 264 | RSpec.describe MyNiceClass do 265 | in_context "with my_var defined" 266 | in_context "without my_var defined" 267 | end 268 | ``` 269 | Will print "MyNiceClass with my_var defined works" and "MyNiceClass without my_var defined doesn't work". Which is valid and readable documentation. 270 | 271 | ## Development 272 | 273 | 274 | After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 275 | 276 | After setuping the repo, you should run `overcommit --install` to install the different hooks. 277 | 278 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 279 | 280 | ## Contributing 281 | 282 | Bug reports and pull requests are welcome on GitHub at https://github.com/denispasin/rspec_in_context. 283 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | task default: :spec 5 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "rspec_in_context" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /lib/rspec_in_context.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_support/all' 4 | require 'rspec_in_context/version' 5 | require 'rspec_in_context/in_context' 6 | require 'rspec_in_context/context_management' 7 | 8 | # Main wrapping module 9 | module RspecInContext 10 | # @api private 11 | # Inclusion convenience of the gem in RSpec 12 | def self.included(base) 13 | base.include(RspecInContext::InContext) 14 | end 15 | end 16 | 17 | # RSpec 18 | module RSpec 19 | # Allows you to define contexts outside of RSpec.describe blocks 20 | # 21 | # @param name [String, Symbol] Name of the defined context 22 | # @param namespace [String, Symbol] Namespace where to store your context 23 | # @param ns Alias of namespace 24 | # @param silent [Boolean] Does the in_context should wrap itself into a context block with its name 25 | # @param print_context [Boolean] Reverse alias of silent 26 | # @param block [Proc] code that will be injected later 27 | def self.define_context(name, namespace: nil, ns: nil, silent: true, print_context: nil, &block) 28 | namespace ||= ns 29 | silent = print_context.nil? ? silent : !print_context 30 | RspecInContext::InContext.outside_define_context(name, namespace, silent, &block) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/rspec_in_context/context_management.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RspecInContext 4 | # Allow context to be scoped inside a block 5 | module ContextManagement 6 | # @api private 7 | # prepending a RSpec method so we can know when a describe/context block finish 8 | # its reading 9 | def subclass(parent, description, args, registration_collection, &example_group_block) 10 | subclass = super 11 | RspecInContext::InContext.remove_context(subclass) 12 | subclass 13 | end 14 | end 15 | end 16 | 17 | module RSpec 18 | # Core 19 | module Core 20 | # ExampleGroup 21 | class ExampleGroup 22 | class << self 23 | # allow context management to work 24 | prepend RspecInContext::ContextManagement 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/rspec_in_context/in_context.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Base module 4 | module RspecInContext 5 | # Error type when no context is find from its name (and eventualy namespace) 6 | class NoContextFound < StandardError; end 7 | 8 | # Context struct 9 | # @attr [Proc] block what will be executed in the test context 10 | # @attr [Class] owner current rspec context class. This will be used to know where a define_context has been defined 11 | # @attr [String | Symbol] name represent the name by which the context can be find. 12 | # @attr [String | Symbol] namespace namespace for context names to avoid collisions 13 | # @attr [Boolean] silent does the in_context wrap itself into a context with its name or an anonymous context 14 | Context = Struct.new(:block, :owner, :name, :namespace, :silent) 15 | 16 | # Main module containing almost every methods 17 | module InContext 18 | # Name of the Global context 19 | GLOBAL_CONTEXT = :global_context 20 | class << self 21 | # Hook for easier inclusion of the gem in RSpec 22 | # @api private 23 | def included(base) 24 | base.extend ClassMethods 25 | end 26 | 27 | # Contexts container + creation 28 | # @api private 29 | def contexts 30 | @contexts ||= HashWithIndifferentAccess.new { |hash, key| hash[key] = HashWithIndifferentAccess.new } 31 | end 32 | 33 | # Meta method to add a new context 34 | # @api private 35 | # 36 | # @note Will warn if a context is overriden 37 | def add_context(context_name, owner = nil, namespace = nil, silent = true, &block) 38 | namespace ||= GLOBAL_CONTEXT 39 | warn("Overriding an existing context: #{context_name}@#{namespace}") if contexts[namespace][context_name] 40 | contexts[namespace][context_name] = Context.new(block, owner, context_name, namespace, silent) 41 | end 42 | 43 | # Find a context. 44 | # @api private 45 | def find_context(context_name, namespace = nil) 46 | if namespace&.present? 47 | contexts[namespace][context_name] 48 | else 49 | contexts[GLOBAL_CONTEXT][context_name] || find_context_in_any_namespace(context_name) 50 | end || (raise NoContextFound, "No context found with name #{context_name}") 51 | end 52 | 53 | # Look into every namespace to find the context 54 | # @api private 55 | def find_context_in_any_namespace(context_name) 56 | valid_namespace = contexts.find { |_, namespaced_contexts| namespaced_contexts[context_name] }&.last 57 | valid_namespace[context_name] if valid_namespace 58 | end 59 | 60 | # @api private 61 | # Delete a context 62 | def remove_context(current_class) 63 | contexts.each_value do |namespaced_contexts| 64 | namespaced_contexts.delete_if { |_, context| context.owner == current_class } 65 | end 66 | end 67 | 68 | # @api private 69 | # Define a context from outside a RSpec.describe block 70 | def outside_define_context(context_name, namespace, silent, &block) 71 | InContext.add_context(context_name, nil, namespace, silent, &block) 72 | end 73 | end 74 | 75 | # This module define the methods that will be available for the end user inside RSpec tests 76 | module ClassMethods 77 | # Use a context and inject its content at this place in the code 78 | # 79 | # @param [String, Symbol] context_name The context namespace 80 | # @param [*Any] args Any arg to be passed down to the injected context 81 | # @param [String, Symbol] namespace namespace name where to look for the context 82 | # @param [String, Symbol] ns Alias for :namespace 83 | # @param block Content that will be re-injected (see #execute_tests) 84 | def in_context(context_name, *args, namespace: nil, ns: nil, &block) 85 | namespace ||= ns 86 | Thread.current[:test_block] = block 87 | context_to_exec = InContext.find_context(context_name, namespace) 88 | return context { instance_exec(*args, &context_to_exec.block) } if context_to_exec.silent 89 | 90 | context(context_name.to_s) { instance_exec(*args, &context_to_exec.block) } 91 | end 92 | 93 | # Used in context definition 94 | # Place where you want to re-inject code passed in argument of in_context 95 | # 96 | # For convenience and readability, a `instanciate_context` alias have been defined 97 | # (for more examples look at tests) 98 | def execute_tests 99 | instance_exec(&Thread.current[:test_block]) if Thread.current[:test_block] 100 | end 101 | alias instanciate_context execute_tests 102 | 103 | # Let you define a context that can be reused later 104 | # 105 | # @param context_name [String, Symbol] The name of the context that will be re-used later 106 | # @param namespace [String, Symbol] namespace name where the context will be stored. 107 | # It helps reducing colisions when you define "global" contexts 108 | # @param ns [String, Symbol] Alias of namespace 109 | # @param block [Proc] Contain the code that will be injected with #in_context later 110 | # @param silent [Boolean] Does the in_context wrap itself into a context with its name or an anonymous context 111 | # @param print_context [Boolean] Reverse alias of silent 112 | # 113 | # @note contexts are scoped to the block they are defined in. 114 | def define_context(context_name, namespace: nil, ns: nil, silent: true, print_context: nil, &block) 115 | namespace ||= ns 116 | silent = print_context.nil? ? silent : !print_context 117 | instance_exec do 118 | InContext.add_context(context_name, hooks.instance_variable_get(:@owner), namespace, silent, &block) 119 | end 120 | end 121 | end 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /lib/rspec_in_context/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RspecInContext 4 | # Version of the gem 5 | VERSION = '1.1.0.3' 6 | end 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rspec_in_context", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "git@github.com:denispasin/rspec_in_context.git", 6 | "author": "Denis Pasin ", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "@prettier/plugin-ruby": "^1.3.0", 10 | "prettier": "^2.2.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /rspec_in_context.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('lib', __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require "rspec_in_context/version" 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = "rspec_in_context" 9 | spec.version = RspecInContext::VERSION 10 | spec.authors = ["Denis Pasin"] 11 | spec.email = ["denis@pasin.fr"] 12 | 13 | spec.summary = 'This gem is here to help DRYing your tests cases by giving a better "shared_examples".' 14 | spec.homepage = "https://github.com/denispasin/rspec_in_context" 15 | 16 | # Specify which files should be added to the gem when it is released. 17 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 18 | spec.files = 19 | Dir.chdir(File.expand_path(__dir__)) do 20 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 21 | end 22 | spec.bindir = "exe" 23 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 24 | spec.require_paths = ["lib"] 25 | spec.required_ruby_version = '>= 2.5.8' # rubocop:disable Gemspec/RequiredRubyVersion 26 | spec.license = 'MIT' 27 | 28 | spec.add_dependency "activesupport", "> 2.0" 29 | spec.add_dependency "rspec", "> 3.0" 30 | 31 | spec.add_development_dependency "bundler" 32 | spec.add_development_dependency "bundler-audit", "> 0.6.0" 33 | spec.add_development_dependency "codacy-coverage", '>= 2.1.0' 34 | spec.add_development_dependency "faker", "> 1.8" 35 | spec.add_development_dependency "guard-rspec", "> 4.7" 36 | spec.add_development_dependency "overcommit", '> 0.46' 37 | spec.add_development_dependency "prettier" 38 | spec.add_development_dependency "rake", "~> 12.0" 39 | spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.1" 40 | spec.add_development_dependency "rubocop", "> 0.58" 41 | spec.add_development_dependency "rubocop-performance" 42 | spec.add_development_dependency "simplecov", "> 0.16" 43 | spec.add_development_dependency "solargraph" 44 | spec.add_development_dependency "yard" 45 | end 46 | -------------------------------------------------------------------------------- /spec/rspec_in_context/context_management_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe RspecInContext::ContextManagement do 4 | describe 'within a describe block' do 5 | define_context 'simple describe test' do 6 | it 'is well scoped' do 7 | expect(true).to be_truthy 8 | end 9 | end 10 | 11 | in_context 'simple describe test' 12 | 13 | context 'within a sub context' do 14 | in_context 'simple describe test' 15 | end 16 | 17 | describe 'within a sub describe' do 18 | in_context 'simple describe test' 19 | end 20 | end 21 | 22 | context 'within a context block' do 23 | define_context 'simple context test' do 24 | it 'is well scoped' do 25 | expect(true).to be_truthy 26 | end 27 | end 28 | 29 | in_context 'simple context test' 30 | 31 | context 'within a sub context' do 32 | in_context 'simple context test' 33 | end 34 | 35 | describe 'within a sub describe' do 36 | in_context 'simple context test' 37 | end 38 | 39 | test_inexisting_context 'simple describe test' 40 | end 41 | 42 | test_inexisting_context 'simple describe test', 'using in_context in a child context' 43 | test_inexisting_context 'simple context test', 'using in_context in a child context' 44 | end 45 | -------------------------------------------------------------------------------- /spec/rspec_in_context/in_context_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.define_context 'outside in_context' do 4 | it 'works for outside context' do 5 | expect(true).to be_truthy 6 | end 7 | end 8 | 9 | RSpec.define_context 'outside namespaced', namespace: 'outside', silent: false do 10 | it 'works' do 11 | expect(true).to be_truthy 12 | end 13 | end 14 | 15 | RSpec.define_context 'outside short-namespaced', ns: 'outside', silent: false do 16 | it 'works' do 17 | expect(true).to be_truthy 18 | end 19 | end 20 | 21 | RSpec.define_context 'silent outside in_context' do 22 | $outside_in_context_class_silent = hooks.instance_variable_get(:@owner) 23 | 24 | it 'is silent by default' do 25 | expect($outside_in_context_class_silent.name.gsub(/::Anonymous(_\d)?/, '')).to eq($current_class.name) 26 | end 27 | end 28 | 29 | RSpec.define_context 'not silent outside in_context', silent: false do 30 | $outside_in_context_class_not_silent = hooks.instance_variable_get(:@owner) 31 | 32 | it 'is not silent' do 33 | expect($current_class).not_to eq($outside_in_context_class_not_silent) 34 | end 35 | end 36 | 37 | RSpec.define_context 'print_context outside in_context', print_context: true do 38 | $outside_in_context_class_print_context = hooks.instance_variable_get(:@owner) 39 | 40 | it 'is not silent' do 41 | expect($current_class).not_to eq($outside_in_context_class_print_context) 42 | end 43 | end 44 | 45 | describe RspecInContext::InContext do 46 | define_context 'inside in_context' do 47 | it 'works for inside context' do 48 | expect(true).to be_truthy 49 | end 50 | end 51 | 52 | define_context :with_symbol do 53 | it 'works both with and without symbols' do 54 | expect(true).to be_truthy 55 | end 56 | end 57 | 58 | define_context 'with test block' do 59 | it "doesn't find unexistant variable" do 60 | expect(defined?(new_var)).to be_falsy 61 | end 62 | 63 | context 'with new variable' do 64 | let(:new_var) { true } 65 | 66 | execute_tests 67 | end 68 | end 69 | 70 | define_context 'with instanciate block' do 71 | it "doesn't find unexistant variable" do 72 | expect(defined?(new_var)).to be_falsy 73 | end 74 | 75 | context 'with variable instanciated' do 76 | instanciate_context 77 | 78 | it 'works with another variable' do 79 | expect(another_var).to eq(:value) 80 | end 81 | end 82 | end 83 | 84 | define_context 'with argument' do |name| 85 | it "doesn't find #{name}" do 86 | expect(defined?(outside_var)).to be_falsy 87 | end 88 | 89 | context "with #{name}" do 90 | let(name) { true } 91 | 92 | execute_tests 93 | end 94 | end 95 | 96 | define_context :nested do 97 | context 'with inside_var defined' do 98 | let(:inside_var) { true } 99 | 100 | it 'works in nested in_context' do 101 | expect(outside_var).to eq(inside_var) 102 | end 103 | end 104 | end 105 | 106 | define_context 'in_context in in_context' do 107 | in_context 'with argument', :inside do 108 | it 'works to use a in_context inside a define_context' do 109 | expect(inside).to be_truthy 110 | end 111 | end 112 | end 113 | 114 | describe 'overriding an existing context' do 115 | before { expect(RspecInContext::InContext).to receive(:warn) } 116 | 117 | RSpec.define_context(:oustide_context) {} 118 | 119 | it 'warns' do 120 | RSpec.define_context(:oustide_context) 121 | end 122 | end 123 | 124 | describe 'in_context calls' do 125 | in_context 'outside in_context' 126 | in_context 'inside in_context' 127 | in_context 'with_symbol' 128 | 129 | in_context 'with test block' do 130 | it 'works with new_var' do 131 | expect(new_var).to be_truthy 132 | end 133 | end 134 | 135 | in_context 'with instanciate block' do 136 | let(:another_var) { :value } 137 | end 138 | 139 | in_context 'with argument', :outside_var do 140 | it 'works with outside_var' do 141 | expect(outside_var).to be_truthy 142 | end 143 | 144 | in_context :nested 145 | end 146 | 147 | in_context 'in_context in in_context' 148 | end 149 | 150 | describe 'silent and print_context options' do 151 | $current_class = hooks.instance_variable_get(:@owner) 152 | after(:all) do 153 | $current_class = nil 154 | $in_context_class_silent = nil 155 | $in_context_class_not_silent = nil 156 | $in_context_class_print_context = nil 157 | $outside_in_context_class_not_silent = nil 158 | $outside_in_context_class_print_context = nil 159 | $outside_in_context_class_silent = nil 160 | end 161 | 162 | define_context 'silent context' do 163 | $in_context_class_silent = hooks.instance_variable_get(:@owner) 164 | 165 | it 'is silent by default' do 166 | expect($current_class.name).to eq($in_context_class_silent.name.gsub(/::Anonymous(_\d)?/, '')) 167 | end 168 | end 169 | 170 | define_context 'not silent context', silent: false do 171 | $in_context_class_not_silent = hooks.instance_variable_get(:@owner) 172 | 173 | it 'is not silent' do 174 | expect($current_class).not_to eq($in_context_class_not_silent) 175 | end 176 | end 177 | 178 | define_context 'print_context context', print_context: true do 179 | $in_context_class_print_context = hooks.instance_variable_get(:@owner) 180 | 181 | it 'is not silent' do 182 | expect($current_class).not_to eq($in_context_class_print_context) 183 | end 184 | end 185 | 186 | in_context 'silent context' 187 | in_context 'not silent context' 188 | in_context 'print_context context' 189 | in_context 'silent outside in_context' 190 | in_context 'not silent outside in_context' 191 | in_context 'print_context outside in_context' 192 | end 193 | 194 | describe 'namespacing' do 195 | in_context 'outside namespaced' 196 | in_context 'outside namespaced', namespace: :outside 197 | in_context 'outside namespaced', ns: 'outside' 198 | in_context 'outside short-namespaced', ns: :outside 199 | test_inexisting_context 'outside namespaced', namespace: :not_exist 200 | 201 | define_context 'inside namespaced', namespace: :inside, silent: false do 202 | it 'works' do 203 | expect(true).to be_truthy 204 | end 205 | end 206 | 207 | define_context :inside, ns: :inside, silent: false do 208 | it 'works' do 209 | expect(true).to be_truthy 210 | end 211 | end 212 | 213 | define_context 'inside namespaced', ns: :inside2, silent: false do 214 | it 'works' do 215 | expect(true).to be_truthy 216 | end 217 | end 218 | 219 | in_context 'inside namespaced' 220 | in_context 'inside namespaced', namespace: :inside 221 | in_context :inside, ns: :inside 222 | in_context 'inside namespaced', ns: :inside 223 | in_context 'inside namespaced', ns: :inside2 224 | test_inexisting_context 'inside namespaced', namespace: :not_exist 225 | describe 'context isolation still work' do 226 | define_context 'isolated namespaced', ns: :isolated, silent: false do 227 | it 'works' do 228 | expect(true).to be_truthy 229 | end 230 | end 231 | in_context 'isolated namespaced', ns: :isolated 232 | in_context :inside, ns: :inside 233 | end 234 | test_inexisting_context 'isolated namespaced' 235 | test_inexisting_context 'isolated namespaced', ns: :isolated 236 | end 237 | end 238 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'simplecov' 4 | require 'faker' 5 | require 'codacy-coverage' 6 | 7 | Codacy::Reporter.start 8 | 9 | SimpleCov.at_exit do 10 | SimpleCov.result.format! 11 | SimpleCov.minimum_coverage 90 12 | SimpleCov.minimum_coverage_by_file 80 13 | end 14 | 15 | SimpleCov.start do 16 | load_profile 'test_frameworks' 17 | add_filter { |source_file| source_file.lines.count < 5 } 18 | end 19 | 20 | require_relative '../lib/rspec_in_context' 21 | 22 | Dir['./spec/support/**/*.rb'].sort.each { |f| require f } 23 | 24 | # This file was generated by the `rspec --init` command. Conventionally, all 25 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 26 | # The generated `.rspec` file contains `--require spec_helper` which will cause 27 | # this file to always be loaded, without a need to explicitly require it in any 28 | # files. 29 | # 30 | # Given that it is always loaded, you are encouraged to keep this file as 31 | # light-weight as possible. Requiring heavyweight dependencies from this file 32 | # will add to the boot time of your test suite on EVERY test run, even for an 33 | # individual file that may not need all of that loaded. Instead, consider making 34 | # a separate helper file that requires the additional dependencies and performs 35 | # the additional setup, and require it from the spec files that actually need 36 | # it. 37 | # 38 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 39 | RSpec.configure do |config| 40 | # rspec-expectations config goes here. You can use an alternate 41 | # assertion/expectation library such as wrong or the stdlib/minitest 42 | # assertions if you prefer. 43 | config.expect_with :rspec do |expectations| 44 | # This option will default to `true` in RSpec 4. It makes the `description` 45 | # and `failure_message` of custom matchers include text for helper methods 46 | # defined using `chain`, e.g.: 47 | # be_bigger_than(2).and_smaller_than(4).description 48 | # # => "be bigger than 2 and smaller than 4" 49 | # ...rather than: 50 | # # => "be bigger than 2" 51 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 52 | end 53 | 54 | # rspec-mocks config goes here. You can use an alternate test double 55 | # library (such as bogus or mocha) by changing the `mock_with` option here. 56 | config.mock_with :rspec do |mocks| 57 | # Prevents you from mocking or stubbing a method that does not exist on 58 | # a real object. This is generally recommended, and will default to 59 | # `true` in RSpec 4. 60 | mocks.verify_partial_doubles = true 61 | end 62 | 63 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will 64 | # have no way to turn it off -- the option exists only for backwards 65 | # compatibility in RSpec 3). It causes shared context metadata to be 66 | # inherited by the metadata hash of host groups and examples, rather than 67 | # triggering implicit auto-inclusion in groups with matching metadata. 68 | config.shared_context_metadata_behavior = :apply_to_host_groups 69 | 70 | # The settings below are suggested to provide a good initial experience 71 | # with RSpec, but feel free to customize to your heart's content. 72 | # # This allows you to limit a spec run to individual examples or groups 73 | # # you care about by tagging them with `:focus` metadata. When nothing 74 | # # is tagged with `:focus`, all examples get run. RSpec also provides 75 | # # aliases for `it`, `describe`, and `context` that include `:focus` 76 | # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 77 | # config.filter_run_when_matching :focus 78 | # 79 | # # Allows RSpec to persist some state between runs in order to support 80 | # # the `--only-failures` and `--next-failure` CLI options. We recommend 81 | # # you configure your source control system to ignore this file. 82 | # config.example_status_persistence_file_path = "spec/examples.txt" 83 | # 84 | # # Limits the available syntax to the non-monkey patched syntax that is 85 | # # recommended. For more details, see: 86 | # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 87 | # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 88 | # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 89 | # config.disable_monkey_patching! 90 | # 91 | # # This setting enables warnings. It's recommended, but in some cases may 92 | # # be too noisy due to issues in dependencies. 93 | # config.warnings = true 94 | # 95 | # # Many RSpec users commonly either run the entire suite or an individual 96 | # # file, and it's useful to allow more verbose output when running an 97 | # # individual spec file. 98 | # if config.files_to_run.one? 99 | # # Use the documentation formatter for detailed output, 100 | # # unless a formatter has already been configured 101 | # # (e.g. via a command-line flag). 102 | # config.default_formatter = "doc" 103 | # end 104 | # 105 | # # Print the 10 slowest examples and example groups at the 106 | # # end of the spec run, to help surface which specs are running 107 | # # particularly slow. 108 | # config.profile_examples = 10 109 | # 110 | # # Run specs in random order to surface order dependencies. If you find an 111 | # # order dependency and want to debug it, you can fix the order by providing 112 | # # the seed, which is printed after each run. 113 | # # --seed 1234 114 | 115 | # IMPORTANT: WE ARE ORDER DEPENDANT BECAUSE CONTEXT ISOLATION TESTS ARE HACKY 116 | # config.order = :random 117 | 118 | # # Seed global randomization in this process using the `--seed` CLI option. 119 | # # Setting this allows you to use `--seed` to deterministically reproduce 120 | # # test failures related to randomization by passing the same `--seed` value 121 | # # as the one that triggered the failure. 122 | # Kernel.srand config.seed 123 | config.include RspecInContext 124 | config.extend ContextTestHelper 125 | end 126 | -------------------------------------------------------------------------------- /spec/support/context_test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Not using in_context here because we want to be sure we are no hidding a bug. 4 | module ContextTestHelper 5 | def test_inexisting_context(context_name, description = nil, namespace: nil, ns: nil) 6 | namespace ||= ns 7 | description ||= 'using in_context defined in a another context' 8 | instance_exec do 9 | in_context context_name, ns: namespace 10 | 11 | # If we get there the test has failed T_T 12 | describe description do 13 | it 'is well scoped' do 14 | expect(false).to be_truthy 15 | end 16 | end 17 | rescue RspecInContext::NoContextFound 18 | describe description do 19 | it 'is well scoped' do 20 | expect(true).to be_truthy 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@prettier/plugin-ruby@^1.3.0": 6 | version "1.3.0" 7 | resolved "https://registry.yarnpkg.com/@prettier/plugin-ruby/-/plugin-ruby-1.3.0.tgz#38ec1447ca43121cfe72961ed974038cbcb57ff7" 8 | integrity sha512-8MHLLdHpb0MDmkh+GZa+MQcQVQzYc34Nv5/I5yQv4n14ogLRMs3oi5C9kQSG2PAYLhAwF8EU36OczzVaHrPHoA== 9 | dependencies: 10 | prettier ">=1.10" 11 | 12 | prettier@>=1.10, prettier@^2.2.1: 13 | version "2.2.1" 14 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" 15 | integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== 16 | --------------------------------------------------------------------------------