mardi 27 juin 2017

Testing URL (regex) validation with RSpec

A Rails 4.2 application has several models with attributes containing URLs. URL validation is done at the model with validates :website_url, format: { with: /\A(https?|ftp):\/\/(-\.)?([^\s\/?\.#-]+\.?)+(\/[^\s]*)?\z/i }.

I need to test the URL validation with RSpec 3.5. It is important to ensure that some well-known XSS patterns do not pass validation and that the most commonly used URL patterns pass validation.

Ideally, I'd like to avoid adding one test for each valid and invalid URL I'm testing so the rspec -fd output is not polluted. However, that would probably require creating two tests (one for valid URLs and other for invalid URLs) and adding multiple expectations to each test (one expectation per URL), which does not seem like good idea.

The best solution I've come up with so far are the following shared examples. Can you think of a better way to test URL validation thoroughly?

RSpec.shared_examples "url validation" do |attribute|
  INVALID_URLS = [
      "invalidurl",
      "inval.lid/urlexample",
      "javascript:dangerousJs()//http://www.validurl.com",
      # Literal array is required for \n to be parsed
      "http://www.validurl.com\n<script>dangerousJs();</script>"
  ]

  VALID_URLS = [
      "http://validurl.com",
      "http://ift.tt/2ufhCLR"
  ]

  INVALID_URLS.each do |url|
    it "is invalid with #{url} in #{attribute}" do
      object = FactoryGirl.build(factory_name(subject), attribute => url)
      object.valid?
      expect(object.errors[attribute]).to include("is invalid")
    end
  end

  VALID_URLS.each do |url|
    it "is valid with #{url} in #{attribute}" do
      object = FactoryGirl.build(factory_name(subject), attribute => url)
      object.valid?
      expect(object).to be_valid
    end
  end
end

Within the model specs:

include_examples "url validation", :website_url

Aucun commentaire:

Enregistrer un commentaire