{"id":13878962,"url":"https://github.com/kucaahbe/rspec-html-matchers","last_synced_at":"2025-05-15T23:05:20.455Z","repository":{"id":1367714,"uuid":"1318075","full_name":"kucaahbe/rspec-html-matchers","owner":"kucaahbe","description":"Old school have_tag, with_tag(and more) matchers for rspec 3 (Nokogiri powered)","archived":false,"fork":false,"pushed_at":"2023-11-08T07:58:22.000Z","size":432,"stargazers_count":198,"open_issues_count":3,"forks_count":43,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-10T04:09:13.407Z","etag":null,"topics":["rspec","ruby","testing"],"latest_commit_sha":null,"homepage":"http://rubygems.org/gems/rspec-html-matchers","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/kucaahbe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2011-02-01T21:50:58.000Z","updated_at":"2025-01-26T11:24:38.000Z","dependencies_parsed_at":"2024-01-13T20:56:24.316Z","dependency_job_id":"fb7d7abf-f967-4dad-8a2a-6fadd019d703","html_url":"https://github.com/kucaahbe/rspec-html-matchers","commit_stats":{"total_commits":355,"total_committers":26,"mean_commits":"13.653846153846153","dds":"0.16619718309859155","last_synced_commit":"c1b555e36e695ba0b09f91a5f8ef4af0d1f55d14"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucaahbe%2Frspec-html-matchers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucaahbe%2Frspec-html-matchers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucaahbe%2Frspec-html-matchers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kucaahbe%2Frspec-html-matchers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kucaahbe","download_url":"https://codeload.github.com/kucaahbe/rspec-html-matchers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436944,"owners_count":22070946,"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":["rspec","ruby","testing"],"created_at":"2024-08-06T08:02:05.470Z","updated_at":"2025-05-15T23:05:15.442Z","avatar_url":"https://github.com/kucaahbe.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# rspec-html-matchers [![Gem Version](https://badge.fury.io/rb/rspec-html-matchers.svg)](https://badge.fury.io/rb/rspec-html-matchers)\n\n[RSpec](https://www.relishapp.com/rspec) matchers for testing your html (for [RSpec 2](https://www.relishapp.com/rspec/rspec-core/v/2-99/docs) use 0.5.x version).\n\n[![RSpec MRI](https://github.com/kucaahbe/rspec-html-matchers/actions/workflows/rspec-mri.yml/badge.svg)](https://github.com/kucaahbe/rspec-html-matchers/actions/workflows/rspec-mri.yml)\n[![RSpec JRuby](https://github.com/kucaahbe/rspec-html-matchers/actions/workflows/rspec-jruby.yml/badge.svg)](https://github.com/kucaahbe/rspec-html-matchers/actions/workflows/rspec-jruby.yml)\n[![Cucumber MRI](https://github.com/kucaahbe/rspec-html-matchers/actions/workflows/cucumber-mri.yml/badge.svg)](https://github.com/kucaahbe/rspec-html-matchers/actions/workflows/cucumber-mri.yml)\n\nGoals\n-----\n\n* designed for testing **complex** html output. If you plan to perform simple matching, consider using:\n  * [assert_select](https://api.rubyonrails.org/classes/ActionDispatch/Assertions/SelectorAssertions.html#method-i-assert_select)\n  * [matchers provided out of the box in rspec-rails](https://rspec.info/features/6-0/rspec-rails/view-specs/view-spec/)\n  * [matchers provided by capybara](https://rdoc.info/github/jnicklas/capybara/Capybara/Node/Matchers)\n* developer-friendly output in error messages\n* built on top of [nokogiri](https://www.nokogiri.org/)\n* has support for [capybara](https://github.com/jnicklas/capybara), see below\n* syntax is similar to `have_tag` matcher from rspec-rails 1.x, but with own syntactic sugar\n* framework agnostic, as input should be `String` (or capybara's page, see below)\n\nInstall\n-------\n\nAdd to your Gemfile in the `:test` group:\n\n```ruby\ngem 'rspec-html-matchers'\n```\n\nInclude it in your RSpec configuration:\n\n```ruby\nRSpec.configure do |config|\n  config.include RSpecHtmlMatchers\nend\n```\n\nor just in your spec(s):\n\n```ruby\ndescribe \"my view spec\" do\n  include RSpecHtmlMatchers\n\n  it \"has tags\" do\n    expect(rendered).to have_tag('div')\n  end\nend\n```\n\nCucumber configuration:\n\n```ruby\nWorld RSpecHtmlMatchers\n```\n\nas this gem requires **nokogiri**, here are [instructions for installing it](https://nokogiri.org/tutorials/installing_nokogiri.html).\n\nUsage\n-----\n\nso perhaps your code produces following output:\n\n```html\n\u003ch1\u003eSimple Form\u003c/h1\u003e\n\u003cform action=\"/users\" method=\"post\"\u003e\n\u003cp\u003e\n  \u003cinput type=\"email\" name=\"user[email]\" /\u003e\n\u003c/p\u003e\n\u003cp\u003e\n  \u003cinput type=\"submit\" id=\"special_submit\" /\u003e\n\u003c/p\u003e\n\u003c/form\u003e\n```\n\nso you test it with the following:\n\n```ruby\nexpect(rendered).to have_tag('form', :with =\u003e { :action =\u003e '/users', :method =\u003e 'post' }) do\n  with_tag \"input\", :with =\u003e { :name =\u003e \"user[email]\", :type =\u003e 'email' }\n  with_tag \"input#special_submit\", :count =\u003e 1\n  without_tag \"h1\", :text =\u003e 'unneeded tag'\n  without_tag \"p\",  :text =\u003e /content/i\nend\n```\n\nExample above should be self-descriptive, if not, please refer to the [`have_tag`](https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers%3Ahave_tag) documentation\n\nInput can be any html string. Let's take a look at these examples:\n\n* matching tags by css:\n\n  ```ruby\n  # simple examples:\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p')\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag(:p)\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p#qwerty')\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p.qwe.rty')\n  # more complicated examples:\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003e\u003cstrong\u003ePara\u003c/strong\u003egraph\u003c/p\u003e').to have_tag('p strong')\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003e\u003cstrong\u003ePara\u003c/strong\u003egraph\u003c/p\u003e').to have_tag('p#qwerty strong')\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003e\u003cstrong\u003ePara\u003c/strong\u003egraph\u003c/p\u003e').to have_tag('p.qwe.rty strong')\n  # or you can use another syntax for examples above\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003e\u003cstrong\u003ePara\u003c/strong\u003egraph\u003c/p\u003e').to have_tag('p') do\n    with_tag('strong')\n  end\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003e\u003cstrong\u003ePara\u003c/strong\u003egraph\u003c/p\u003e').to have_tag('p#qwerty') do\n    with_tag('strong')\n  end\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003e\u003cstrong\u003ePara\u003c/strong\u003egraph\u003c/p\u003e').to have_tag('p.qwe.rty') do\n    with_tag('strong')\n  end\n  ```\n\n* special case for classes matching:\n\n  ```ruby\n  # all of this are equivalent:\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :with =\u003e { :class =\u003e 'qwe rty' })\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :with =\u003e { :class =\u003e 'rty qwe' })\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :with =\u003e { :class =\u003e ['rty', 'qwe'] })\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :with =\u003e { :class =\u003e ['qwe', 'rty'] })\n  ```\n\n  The same works with `:without`:\n\n  ```ruby\n  # all of this are equivalent:\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :without =\u003e { :class =\u003e 'qwe rty' })\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :without =\u003e { :class =\u003e 'rty qwe' })\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :without =\u003e { :class =\u003e ['rty', 'qwe'] })\n  expect('\u003cp class=\"qwe rty\" id=\"qwerty\"\u003eParagraph\u003c/p\u003e').to have_tag('p', :without =\u003e { :class =\u003e ['qwe', 'rty'] })\n  ```\n\n* content matching:\n\n  ```ruby\n  expect('\u003cp\u003e Some content\u0026nbsphere\u003c/p\u003e').to have_tag('p', :text =\u003e ' Some content here')\n  # or\n  expect('\u003cp\u003e Some content\u0026nbsphere\u003c/p\u003e').to have_tag('p') do\n    with_text ' Some content here'\n  end\n\n  expect('\u003cp\u003e Some content\u0026nbsphere\u003c/p\u003e').to have_tag('p', :text =\u003e /Some content here/)\n  # or\n  expect('\u003cp\u003e Some content\u0026nbsphere\u003c/p\u003e').to have_tag('p') do\n    with_text /Some content here/\n  end\n\n  # mymock.text == 'Some content here'\n  expect('\u003cp\u003e Some content\u0026nbsphere\u003c/p\u003e').to have_tag('p', :text =\u003e mymock.text)\n  # or\n  expect('\u003cp\u003e Some content\u0026nbsphere\u003c/p\u003e').to have_tag('p') do\n    with_text mymock.text\n  end\n\n  # matching text content as it's seen by user:\n  rendered = \u003c\u003cHTML\n  \u003cp\u003e\n     content with ignored spaces around\n  \u003c/p\u003e\n  HTML\n  expect(rendered).to have_tag('p', :seen =\u003e 'content with ignored spaces around')\n  ```\n\n* usage with capybara and cucumber:\n\n  ```ruby\n  expect(page).to have_tag( ... )\n  ```\n\nwhere `page` is an instance of Capybara::Session\n\n* also included shorthand matchers for form inputs:\n\n  - have\\_form\n  - with\\_checkbox\n  - with\\_email\\_field\n  - with\\_file\\_field\n  - with\\_hidden\\_field\n  - with\\_option\n  - with\\_password\\_field\n  - with\\_radio\\_button\n  - with\\_button\n  - with\\_select\n  - with\\_submit\n  - with\\_text\\_area\n  - with\\_text\\_field\n  - with\\_url\\_field\n  - with\\_number\\_field\n  - with\\_range\\_field\n  - with\\_date\\_field\n\nand of course you can use the `without_` matchers,\nfor more info take a look at [documentation](https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers)\n\n### rspec 1 partial backwards compatibility:\n\nyou can match:\n\n```ruby\nexpect(response).to have_tag('div', 'expected content')\nexpect(response).to have_tag('div', /regexp matching expected content/)\n```\n\n[RSpec 1 `have_tag` documentation](https://old.rspec.info/rails/writing/views.html)\n\nMatching Tag Attributes\n-----------------------\n\nYou can also match the content of attributes by using selectors. For example, to ensure an `img` tag has an `alt` attribute, you can match:\n\n```ruby\nexpect(index).to have_tag(\"img[alt!='']\")\n```\n\nMore info\n---------\n\nYou can find more on [documentation](https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers)\n\nAlso, please read [CHANGELOG](https://github.com/kucaahbe/rspec-html-matchers/blob/main/CHANGELOG.md) and [issues](https://github.com/kucaahbe/rspec-html-matchers/issues), might be helpful.\n\nContribution\n============\n\n1. Fork the repository\n2. Add tests for your feature\n3. Write the code\n4. Add documentation for your contribution\n5. Send a pull request\n\nContributors\n============\n\n- [Kelly Felkins](https://github.com/kellyfelkins)\n- [Ryan Wilcox](https://github.com/rwilcox)\n- [Simon Schoeters](https://github.com/cimm)\n- [Felix Tjandrawibawa](https://github.com/cemenghttps://github.com/cemeng)\n- [Szymon Przybył](https://github.com/apocalyptiq)\n- [Manuel Meurer](https://github.com/manuelmeurer)\n- [Andreas Riemer](https://github.com/arfl)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkucaahbe%2Frspec-html-matchers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkucaahbe%2Frspec-html-matchers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkucaahbe%2Frspec-html-matchers/lists"}