Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/masaakiaoyagi/rspec-context_helper.rb

context helpers for RSpec
https://github.com/masaakiaoyagi/rspec-context_helper.rb

rspec ruby testing

Last synced: 4 months ago
JSON representation

context helpers for RSpec

Awesome Lists containing this project

README

        

# RSpec::ContextHelper

https://github.com/masaakiaoyagi/rspec-context_helper.rb/releases[image:https://img.shields.io/github/v/release/masaakiaoyagi/rspec-context_helper.rb?include_prereleases[GitHub release (latest SemVer including pre-releases)]]
https://github.com/masaakiaoyagi/rspec-context_helper.rb/actions/workflows/test.yml[image:https://github.com/masaakiaoyagi/rspec-context_helper.rb/actions/workflows/test.yml/badge.svg[test]]
https://opensource.org/licenses/MIT[image:https://img.shields.io/badge/License-MIT-yellow.svg[License: MIT]]
https://conventionalcommits.org[image:https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white[Conventional Commits]]

This helper library is for writing tests concisely.

You can write a test as follows.
```ruby
example_with("value is zero", value: 0) { expect(value).to eq 0 }
```
Above is the same as below.
```ruby
context "value is zero" do
let(:value) { 0 }
it { expect(value).to eq 0 }
end
```

That's basically all there is to it, but I think it will be more potent when used with a https://relishapp.com/rspec/rspec-expectations/v/3-11/docs/custom-matchers[custom matcher].

.Example of ActiveModel validation tests using a custom matcher
[%collapsible]
====
```ruby
class Account
include ActiveModel::Model
include ActiveModel::Attributes
attribute :name, :string
validates :name, presence: true, length: { in: 3..20 }, format: { with: /\A[0-9a-zA-Z]*\z/, message: "alphanumeric characters only" }
end

let(:account) { Account.new(name: name) }
before do
account.valid?
end

# There is no "have_error" matcher, so you need to create one.
example_with(name: " ") { expect(account).to have_error.on(:name).with(:blank) }
example_with(name: "a" * 2) { expect(account).to have_error.on(:name).with(:too_short, count: 3) }
example_with(name: "a" * 3) { expect(account).not_to have_error }
example_with(name: "a" * 20) { expect(account).not_to have_error }
example_with(name: "a" * 21) { expect(account).to have_error.on(:name).with(:too_long, count: 20) }
example_with(name: "a0a") { expect(account).not_to have_error }
example_with(name: "a a") { expect(account).to have_error.on(:name).with(:invalid) }
example_with(name: "a@a") { expect(account).to have_error.on(:name).with("alphanumeric characters only") }
```
====

## Installation

. Add the dependency to your `Gemfile`:
+
```ruby
gem "rspec-context_helper"
```

. Run `bundle install`

## Usage

Add the following line to your `spec_helper.rb`:
```ruby
require "rspec/context_helper"
```

See https://github.com/masaakiaoyagi/rspec-context_helper.rb/blob/main/spec/rspec/context_helper_spec.rb[spec] how to write a test.

### API

#### `example_with(description = nil, _meta: nil, _shared: nil, **values, &block)`
Defines an exmaple with metadata, shared context and local variables.

##### parameters
.`description`: context description
[%collapsible]
====
If description is omitted, it is automatically generated from other parameters.
====

.`_meta`: https://relishapp.com/rspec/rspec-core/v/3-11/docs/metadata/user-defined-metadata[metadata] to be defined
[%collapsible]
====
.examples
```ruby
_meta: :foo
_meta: [:foo, :bar]
_meta: { foo: "1" }
_meta: [:foo, bar: 2]
```
====

.`_shared`: https://relishapp.com/rspec/rspec-core/v/3-11/docs/example-groups/shared-context[shared context] to be included
[%collapsible]
====
.examples
```ruby
_shared: :foo
_shared: [:foo, :bar]
_shared: { foo: "1" }
_shared: [:foo, bar: 2]
_shared: { foo: [:arg1, :arg2] }
_shared: { foo: { opt1: :bar } }
_shared: { foo: [:arg1, opt1: :bar] }
```
====

.`values`: helper methods to be defined by https://relishapp.com/rspec/rspec-core/v/3-11/docs/helper-methods/let-and-let[let]
[%collapsible]
====
.You need to use a proc in order to call helper methods in the example context.
[%collapsible]
=====
```ruby
example_with(foo: bar, bar: 2) { expect(foo).to eq 2 }
# => undefined local variable or method `bar'
example_with(foo: -> { bar }, bar: 2) { expect(foo).to eq 2 }
# => OK
```
=====

.So you need to use a *nested* proc in order to define a helper method that returns a proc.
[%collapsible]
=====
```ruby
example_with(foo: -> { "proc" }) { expect(foo.call).to eq "proc" }
# => undefined method `call' for "proc":String
example_with(foo: -> { -> { "proc" } }) { expect(foo.call).to eq "proc" }
# => OK
```
=====

.examples
```ruby
foo: "1"
foo: "1", bar: 2
foo: -> { bar }, bar: 2
foo: -> { -> { "proc" } }
```
====

##### examples
.`example_with("description") { expect(true).to eq true }`
[%collapsible]
====
same as
```ruby
context "description" do
it { expect(true).to eq true }
end
```
====

.`example_with(value: 1) { expect(value).to eq 1 }`
[%collapsible]
====
same as
```ruby
context "when value is 1" do
let(:value) { 1 }
it { expect(value).to eq 1 }
end
```
====

.`example_with(_shared: "logged in") { expect(logged_in).to eq true }`
[%collapsible]
====
same as
```ruby
context "when logged in" do
include_context "logged in"
it { expect(logged_in).to eq true }
end
```
====

.`example_with(_meta: :bar) { |e| expect(e.metadata[:bar]).to eq true }`
[%collapsible]
====
same as
```ruby
context "", :bar do
it { |e| expect(e.metadata[:bar]).to eq true }
end
```
====

.`example_with(_meta: { foo: 1 }) { |e| expect(e.metadata[:foo]).to eq 1 }`
[%collapsible]
====
same as
```ruby
context "", foo: 1 do
it { |e| expect(e.metadata[:foo]).to eq 1 }
end
```
====

#### `context_with(description = nil, _meta: nil, _shared: nil, **values, &block)`
Defines an example group with metadata, shared context and local variables.

##### parameters
same as `example_with`

##### examples
.`context_with("description") { ... }`
[%collapsible]
====
same as
```ruby
context "description" do
...
end
```
====

.`context_with(value: 1) { ... }`
[%collapsible]
====
same as
```ruby
context "when value is 1" do
let(:value) { 1 }
...
end
```
====

.`context_with(_shared: "logged in") { ... }`
[%collapsible]
====
same as
```ruby
context "when logged in" do
include_context "logged in"
...
end
```
====

.`context_with(_meta: :bar) { ... }`
[%collapsible]
====
same as
```ruby
context "", :bar do
...
end
```
====

.`context_with(_meta: { foo: 1 }) { ... }`
[%collapsible]
====
same as
```ruby
context "", foo: 1 do
...
end
```
====

## Development

### Run tests
```sh
$ docker compose run --rm 3.1 bundle exec rspec
```

## See also
* https://github.com/rspec/rspec-metagem[RSpec]
* https://github.com/masaakiaoyagi/spectator-context_helper.cr[Crystal version]