{"id":13521059,"url":"https://github.com/mongoid/mongoid-rspec","last_synced_at":"2025-05-16T19:08:03.585Z","repository":{"id":674043,"uuid":"609739","full_name":"mongoid/mongoid-rspec","owner":"mongoid","description":"RSpec matchers and macros for Mongoid.","archived":false,"fork":false,"pushed_at":"2024-06-05T03:19:29.000Z","size":375,"stargazers_count":499,"open_issues_count":18,"forks_count":176,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-04-20T15:44:28.596Z","etag":null,"topics":["mongoid","rspec-matchers","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mongoid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2010-04-14T08:06:50.000Z","updated_at":"2025-04-16T09:39:41.000Z","dependencies_parsed_at":"2025-04-12T18:43:42.858Z","dependency_job_id":"d92ded94-0ee5-4f51-9858-a3f920cd41df","html_url":"https://github.com/mongoid/mongoid-rspec","commit_stats":{"total_commits":319,"total_committers":75,"mean_commits":4.253333333333333,"dds":0.7366771159874608,"last_synced_commit":"6f0ac2ff9101d8ca79898c6a8f82a461bd242961"},"previous_names":["mongoid-rspec/mongoid-rspec","evansagge/mongoid-rspec"],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoid%2Fmongoid-rspec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoid%2Fmongoid-rspec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoid%2Fmongoid-rspec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoid%2Fmongoid-rspec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mongoid","download_url":"https://codeload.github.com/mongoid/mongoid-rspec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250144907,"owners_count":21382323,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mongoid","rspec-matchers","ruby"],"created_at":"2024-08-01T06:00:27.635Z","updated_at":"2025-05-16T19:08:03.564Z","avatar_url":"https://github.com/mongoid.png","language":"Ruby","readme":"# [mongoid-rspec](https://github.com/mongoid/mongoid-rspec \"A collection of RSpec-compatible matchers that help to test Mongoid documents.\")\n\n[![Gem Version](https://badge.fury.io/rb/mongoid-rspec.svg)](https://badge.fury.io/rb/mongoid-rspec)\n[![Test Status](https://github.com/mongoid/mongoid-rspec/workflows/Test/badge.svg)](https://github.com/mongoid/mongoid-rspec/actions)\n[![Rubocop Status](https://github.com/mongoid/mongoid-rspec/workflows/Rubocop/badge.svg)](https://github.com/mongoid/mongoid-rspec/actions)\n\nThe mongoid-rspec library provides a collection of RSpec-compatible matchers that help to test Mongoid documents.\n\n[Tested](https://github.com/mongoid/mongoid-locker/actions) against:\n- MRI: `2.6.x`, `2.7.x`, `3.0.x`, `3.1.x`, `3.2.x`\n- Mongoid: `4`, `5`, `6`, `7`, `8`, `9`\n\nSee [.github/workflows/rspec.yml](.github/workflows/rspec.yml) for the latest test matrix.\n\n## Installation\n\nDrop this line into your Gemfile:\n\n```ruby\ngroup :test do\n  gem 'mongoid-rspec'\nend\n\n```\n\n## Compatibility\n\nThis gem is compatible with Mongoid 3, 4, 5, 6, 7, 8, 9.\n\n## Configuration\n\n### Rails\n\nAdd to your `rails_helper.rb` file\n\n```ruby\nrequire 'mongoid-rspec'\n\nRSpec.configure do |config|\n  config.include Mongoid::Matchers, type: :model\nend\n```\n\n### Other\n\nAdd to your `spec_helper.rb` file.\n\n```ruby\nrequire 'mongoid-rspec'\n\nRSpec.configure do |config|\n  config.include Mongoid::Matchers\nend\n```\n\n## Matchers\n\n### be_mongoid_document\n\n```ruby\nclass Post\n  include Mongoid::Document\nend\n\nRSpec.describe Post, type: :model do\n  it { is_expected.to be_mongoid_document }\nend\n```\n\n### be_dynamic_document\n\n```ruby\nclass User\n  include Mongoid::Document\n  include Mongoid::Attributes::Dynamic\nend\n\nRSpec.describe User, type: :model do\n  it { is_expected.to be_dynamic_document }\nend\n```\n\n### have_timestamps\n\nWith full timestamps.\n\n```ruby\nclass Log\n  include Mongoid::Document\n  include Mongoid::Timestamps\nend\n\nRSpec.describe Log, type: :model do\n  it { is_expected.to have_timestamps }\nend\n```\n\nWith short timestamps.\n\n```ruby\nclass User\n  include Mongoid::Document\n  include Mongoid::Timestamps::Short\nend\n\nRSpec.describe User, type: :model do\n  it { is_expected.to have_timestamps.shortened }\nend\n```\n\nWith only creating or updating timestamps.\n\n```ruby\nclass Admin\n  include Mongoid::Document\n  include Mongoid::Timestamps::Create\n  include Mongoid::Timestamps::Update\nend\n\nRSpec.describe Admin, type: :model do\n  it { is_expected.to have_timestamps.for(:creating) }\n  it { is_expected.to have_timestamps.for(:updating) }\nend\n```\n\nWith short creating or updating timestamps.\n\n```ruby\nclass Post\n  include Mongoid::Document\n  include Mongoid::Timestamps::Create::Short\nend\n\nRSpec.describe Short, type: :model do\n  it { is_expected.to have_timestamps.for(:creating).shortened }\nend\n```\n\n### be_stored_in\n\n```ruby\nclass Post\n  include Mongoid::Document\n\n  store_in database: 'db1', collection: 'messages', client: 'secondary'\nend\n\nRSpec.describe Post, type: :model do\n  it { is_expected.to be_stored_in(database: 'db1', collection: 'messages', client: 'secondary') }\nend\n```\n\nIt checks only those options, that you specify. For instance, test in example below will pass, even though expectation contains only `database` option.\n\n```ruby\nclass Comment\n  include Mongoid::Document\n\n  store_in database: 'db2', collection: 'messages'\nend\n\nRSpec.describe Comment, type: :model do\n  it { is_expected.to be_stored_in(database: 'db2') }\nend\n```\n\nIt works fine with lambdas and procs.\n\n```ruby\nclass User\n  include Mongoid::Document\n\n  store_in database: -\u003e{ Thread.current[:database] }\nend\n\nRSpec.describe Post, type: :model do\n  it do\n    Thread.current[:database] = 'db3'\n    is_expected.to be_stored_in(database: 'db3')\n\n    Thread.current[:database] = 'db4'\n    is_expected.to be_stored_in(database: 'db4')\n  end\nend\n```\n\n### have_index_for\n\n```ruby\nclass Article\n  index({ title: 1 }, { unique: true, background: true })\n  index({ title: 1, created_at: -1 })\n  index({ category: 1 })\nend\n\nRSpec.describe Article, type: :model do\n  it do\n    is_expected\n      .to have_index_for(title: 1)\n      .with_options(unique: true, background: true)\n  end\n  it { is_expected.to have_index_for(title: 1, created_at: -1) }\n  it { is_expected.to have_index_for(category: 1) }\nend\n```\n\n### Field Matchers\n\n```ruby\nRSpec.describe Article do\n  it { is_expected.to have_field(:published).of_type(Mongoid::Boolean).with_default_value_of(false) }\n  it { is_expected.to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(true) }\n  it { is_expected.not_to have_field(:allow_comments).of_type(Mongoid::Boolean).with_default_value_of(false) }\n  it { is_expected.not_to have_field(:number_of_comments).of_type(Integer).with_default_value_of(1) }\nend\n\nRSpec.describe User do\n  it { is_expected.to have_fields(:email, :login) }\n  it { is_expected.to have_field(:s).with_alias(:status) }\n  it { is_expected.to have_fields(:birthdate, :registered_at).of_type(DateTime) }\nend\n```\n\n### Association Matchers\n\n```ruby\nRSpec.describe User do\n  it { is_expected.to have_many(:articles).with_foreign_key(:author_id).ordered_by(:title) }\n\n  it { is_expected.to have_one(:record) }\n\n  # can verify autobuild is set to true\n  it { is_expected.to have_one(:record).with_autobuild }\n\n  it { is_expected.to have_many :comments }\n\n  # can also specify with_dependent to test if :dependent =\u003e :destroy/:destroy_all/:delete is set\n  it { is_expected.to have_many(:comments).with_dependent(:destroy) }\n\n  # can verify autosave is set to true\n  it { is_expected.to have_many(:comments).with_autosave }\n\n  it { is_expected.to embed_one :profile }\n\n  it { is_expected.to have_and_belong_to_many(:children) }\n  it { is_expected.to have_and_belong_to_many(:children).of_type(User) }\nend\n\nRSpec.describe Profile do\n  it { is_expected.to be_embedded_in(:user).as_inverse_of(:profile) }\nend\n\nRSpec.describe Article do\n  it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles) }\n  it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index }\n  it { is_expected.to embed_many(:comments) }\nend\n\n# when the touch option is provided, then we can also verify that it is set\n\n# by default, with_touch matches true when no parameters are provided\ndescribe Article do\n  it { is_expected.to belong_to(:author).of_type(User).as_inverse_of(:articles).with_index.with_touch }\nend\n\n# parameters are supported for explicit matching\ndescribe Comment do\n  it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments).with_polymorphism.with_touch(true) }\nend\n\ndescribe Permalink do\n  it { is_expected.to be_embedded_in(:linkable).as_inverse_of(:link).with_touch(false) } \nend\n\n# touch can also take a symbol representing a field on the parent to touch\ndescribe Record do\n  it { is_expected.to belong_to(:user).as_inverse_of(:record).with_touch(:record_updated_at) }\nend\n\nRSpec.describe Comment do\n  it { is_expected.to be_embedded_in(:article).as_inverse_of(:comments) }\n  it { is_expected.to belong_to(:user).as_inverse_of(:comments) }\nend\n\nRSpec.describe Record do\n  it { is_expected.to belong_to(:user).as_inverse_of(:record) }\nend\n\nRSpec.describe Site do\n  it { is_expected.to have_many(:users).as_inverse_of(:site).ordered_by(:email.asc).with_counter_cache }\nend\n\nRSpec.describe Message do\n  it { is_expected.to belong_to(:user).with_optional }\nend\n```\n\n### Validation Matchers\n\n```ruby\nRSpec.describe Site do\n  it { is_expected.to validate_presence_of(:name) }\n  it { is_expected.to validate_uniqueness_of(:name) }\nend\n\nRSpec.describe User do\n  it { is_expected.to validate_presence_of(:login) }\n  it { is_expected.to validate_uniqueness_of(:login).scoped_to(:site) }\n  it { is_expected.to validate_uniqueness_of(:email).case_insensitive.with_message(\"is already taken\") }\n  it { is_expected.to validate_format_of(:login).to_allow(\"valid_login\").not_to_allow(\"invalid login\") }\n  it { is_expected.to validate_associated(:profile) }\n  it { is_expected.to validate_exclusion_of(:login).to_not_allow(\"super\", \"index\", \"edit\") }\n  it { is_expected.to validate_inclusion_of(:role).to_allow(\"admin\", \"member\") }\n  it { is_expected.to validate_confirmation_of(:email) }\n  it { is_expected.to validate_presence_of(:age).on(:create, :update) }\n  it { is_expected.to validate_numericality_of(:age).on(:create, :update) }\n  it { is_expected.to validate_inclusion_of(:age).to_allow(23..42).on([:create, :update]) }\n  it { is_expected.to validate_presence_of(:password).on(:create) }\n  it { is_expected.to validate_presence_of(:provider_uid).on(:create) }\n  it { is_expected.to validate_inclusion_of(:locale).to_allow([:en, :ru]) }\nend\n\nRSpec.describe Article do\n  it { is_expected.to validate_length_of(:title).within(8..16) }\n  it { is_expected.to validate_absence_of(:deletion_date) }\nend\n\nRSpec.describe Visitor do\n  it { is_expected.to validate_length_of(:name).with_maximum(160).with_minimum(1) }\nend\n\nRSpec.describe Profile do\n  it { is_expected.to validate_numericality_of(:age).greater_than(0) }\nend\n\nRSpec.describe MovieArticle do\n  it { is_expected.to validate_numericality_of(:rating).to_allow(:greater_than =\u003e 0).less_than_or_equal_to(5) }\n  it { is_expected.to validate_numericality_of(:classification).to_allow(:even =\u003e true, :only_integer =\u003e true, :nil =\u003e false) }\nend\n\nRSpec.describe Person do\n   # in order to be able to use the custom_validate matcher, the custom validator class (in this case SsnValidator)\n   # should redefine the kind method to return :custom, i.e. \"def self.kind() :custom end\"\n  it { is_expected.to custom_validate(:ssn).with_validator(SsnValidator) }\nend\n\n# If you're using validators with if/unless conditionals, spec subject must be object instance\n# This is supported on Mongoid 4 and newer\nRspec.describe User do\n  context 'when user has `admin` role' do\n    subject { User.new(role: 'admin') }\n\n    it { is_expected.to validate_length_of(:password).greater_than(20) }\n  end\n\n  context 'when user does not have `admin` role' do\n    subject { User.new(role: 'member') }\n\n    it { is_expected.not_to validate_length_of(:password) }\n  end\nend\n```\n\n### Mass Assignment Matcher\n\n```ruby\nRSpec.describe User do\n  it { is_expected.to allow_mass_assignment_of(:login) }\n  it { is_expected.to allow_mass_assignment_of(:email) }\n  it { is_expected.to allow_mass_assignment_of(:age) }\n  it { is_expected.to allow_mass_assignment_of(:password) }\n  it { is_expected.to allow_mass_assignment_of(:password) }\n  it { is_expected.to allow_mass_assignment_of(:role).as(:admin) }\n\n  it { is_expected.not_to allow_mass_assignment_of(:role) }\nend\n```\n\n### Accepts Nested Attributes Matcher\n\n```ruby\nRSpec.describe User do\n  it { is_expected.to accept_nested_attributes_for(:articles) }\n  it { is_expected.to accept_nested_attributes_for(:comments) }\nend\n\nRSpec.describe Article do\n  it { is_expected.to accept_nested_attributes_for(:permalink) }\nend\n```\n\n## Contributing\n\nYou're encouraged to contribute to this library. See [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n## Copyright and License\n\nCopyright (c) 2009-2018 Evan Sagge and Contributors.\n\nMIT License. See [LICENSE](LICENSE) for details.\n","funding_links":[],"categories":["Ruby","Matchers"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmongoid%2Fmongoid-rspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmongoid%2Fmongoid-rspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmongoid%2Fmongoid-rspec/lists"}