Rspec/Rails/Nokogiri: Undefined namespace prefix - ruby-on-rails

Here is the output of node.to_xml
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
<ram:GuidelineVersionID>2.1.1</ram:GuidelineVersionID>
</ram:GuidelineSpecifiedDocumentContextParameter>
<ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017:poacc:billing:3.0</ram:ID>
<ram:BusinessProcessVersionID>1.0</ram:BusinessProcessVersionID>
</ram:BusinessProcessSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
Here is the corresponding rspec test:
describe '#to_node' do
subject(:node) { exchanged_document_context.to_node }
it 'returns the XML representation of the document' do
expect(node).to be_a(Nokogiri::XML::Node)
# Check the attributes of the ExchangedDocumentContext node
expect(node.name).to eq('rsm:ExchangedDocumentContext')
puts node.to_xml
# Check the attributes of the GuidelineSpecifiedDocumentContextParameter node
# rspec error is showing for the line below
expect(node.at_xpath('ram:GuidelineSpecifiedDocumentContextParameter')).to be_a(Nokogiri::XML::Node)
# Check the attributes of the BusinessProcessSpecifiedDocumentContextParameter node
expect(node.at_xpath('ram:BusinessProcessSpecifiedDocumentContextParameter')).to be_a(Nokogiri::XML::Node)
end
end
But I'm getting this error:
Nokogiri::XML::XPath::SyntaxError:
ERROR: Undefined namespace prefix: ram:GuidelineSpecifiedDocumentContextParameter

because of the colon symbol (:), the XPath treated ram as a namespace instead of a node.
try this pattern instead:
...
nokogiri.at_xpath("//*[name()='ram:GuidelineSpecifiedDocumentContextParameter']")

Related

RSpec failing because URL is being escaped

Moving RSpec in a Rails project from using Poltergeist to using Selenium (Webdriver) Chrome and now I'm getting some failures I wasn't quite expecting. Looks like it's trying to escape the URL for some reason? Thoughts?
Failures:
1) Story editing private story should be read after editing
Failure/Error: expect(story_cover_image).to eq "#{url}/convert?rotate=exif"
expected: "http://placehold.it/edited.png/convert?rotate=exif"
got: "\"http://placehold.it/edited.png/convert?rotate=exif\""
(compared using ==)
Here's the spec (removed what's not relevant):
feature 'Story editing', type: :feature, js: true do
...
let(:story_attributes) do
{
...
cover_image: {
url: 'http://placehold.it/edited.png'
}
}
end
...
def fill_file_url(url)
execute_script <<-JS
angular.element(".content").scope().story.addCoverImage();
angular.element(".content").scope().story.coverImage.url = "#{url}";
angular.element(".content").scope().story.save();
JS
expect(story_cover_image).to eq "#{url}/convert?rotate=exif"
end
...
def fill_in_story_form(story)
fill_file_url story[:cover_image][:url] if story[:cover_image]
end
...
context 'private' do
scenario 'story should be read after editing' do
fill_in_story_form story_attributes <<<<<< SPEC FAILS ON THIS LINE >>>>>
...
end
end
EDIT New failure after changing "#{url}" to #{url} as per request:
Also tried: angular.element(".content").scope().story.coverImage.url = url;
1) Story editing private story should be read after editing
Failure/Error:
execute_script <<-JS
angular.element(".content").scope().story.addCoverImage();
angular.element(".content").scope().story.coverImage.url = #{url};
angular.element(".content").scope().story.save();
JS
Selenium::WebDriver::Error::UnknownError:
unknown error: Runtime.evaluate threw exception: SyntaxError: Unexpected token :
(Session info: chrome=69.0.3497.100)
(Driver info: chromedriver=2.41.578706 (5f725d1b4f0a4acbf5259df887244095596231db),platform=Mac OS X 10.13.6 x86_64)
The problem is in this line:
angular.element(".content").scope().story.coverImage.url = "#{url}";
Because inside a HEREDOC everything is considered to be a string #{url} is all you need to do string interpolation. But in this case you want the interpolation to be treated as a Javascript string so you should use '#{url}'. Doing "#{url}" creates escaped double-quotes because by default a HEREDOC follows double-quoting rules, so you should change all your double quotes to single quotes inside the HEREDOC.
Trying it directly into the irb console you get:
url = "https://www.google.com"
<<-JS
angular.element('.content').scope().story.coverImage.url = '#{url}';
JS
=> "angular.element('.content').scope().story.coverImage.url = 'https://www.google.com';\n";
<<-JS
angular.element(".content").scope().story.coverImage.url = '#{url}';
JS
=> "angular.element(\".content\").scope().story.coverImage.url = 'http://www.google.com';\n"
Quoting rules of Heredoc docs

RSpec routing spec: sequence of fields in hash

I'm having a problem with the actual vs expected failing due to sequence on the hash. I don't recall seeing this before ... and in any case I thought a hash was unordered?
How can I have this test pass?
RSpec.describe ArticleSectionsController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(:get => "/articles/5/article_sections").to route_to("article_sections#index", article_id: 5)
end
end
end
1) ArticleSectionsController routing routes to #index
Failure/Error: expect(:get => "/articles/5/article_sections").to route_to("article_sections#index", article_id: 5)
The recognized options <{"controller"=>"article_sections", "action"=>"index", "article_id"=>"5"}> did not match <{"article_id"=>5, "controller"=>"article_sections", "action"=>"index"}>, difference:.
--- expected
+++ actual
## -1 +1 ##
-{"article_id"=>5, "controller"=>"article_sections", "action"=>"index"}
+{"controller"=>"article_sections", "action"=>"index", "article_id"=>"5"}
The problem is not the order of the hash, the problem is the content.
"article_id"=>"5"
is not the same as
"article_id"=> 5
Us the string version in your route_to parameters and that'll fix the issue.

How do you use fixtures with attr_encrypted

I want to test a model that uses attr_encrypted to encrypt a secret in the database
class Thing
attr_encrypted :secret, encode: true
end
But when I define the secret in a fixture the encoded newline character gets escaped out.
one:
encrypted_secret: '<%= Thing.encrypt_secret(SecureRandom.uuid) %>'
That is:
'axZFZEknxUSYdUlPhwLBbj8CwSeCW5at2INA98EcCcY7MVFdmXvk7Sb4DZhC\nm6qD\n'
Is stored in the database as:
'axZFZEknxUSYdUlPhwLBbj8CwSeCW5at2INA98EcCcY7MVFdmXvk7Sb4DZhC
m6qD'
The problem with this is that this then fails:
thing = things(:one)
assert_equal thing, Thing.find_by_secret(thing.secret)
Thing.find_by_secret(thing.secret) returns nil because the resulting SQL query tries to match the two versions of the encryped secret and fails to get a match.
I have tried:
one:
encrypted_secret: 'axZFZEknxUSYdUlPhwLBbj8CwSeCW5at2INA98EcCcY7MVFdmXvk7Sb4DZhC\nm6qD\n'
but get the same result.
How can I configure my fixtures to work with attr_encrypted?
A solution that works is to replace all '\n' with '\\n' and use double quotes. This works:
one:
encryped_secret: "<%= Thing.encrypt_secret(SecureRandom.uuid).gsub(/\n/, '\\\\n') %>"
Is there a tidier way to do this?
I faced the same situation under Rails4 + attr_encrypted + fixture + Minitest environment, and here my workaround is.
In summary, I had the following steps:
write plain (= unencrypted) text fixture with a specific file extention (in my case, it is *.yml.noenc).
write rake-task to convert from the plain fixture (.yml.noenc) to encrypted fixture (.yml).
Let me explain the detail below.
For example, "Message" model has two attributes 'name' and 'body' which are required to be encrypted as follows:
class Message < ActiveRecord::Base
attr_encrypted :name, key: ...
attr_encrypted :body, key: ...
...
end
write test/fixtures/messages.yml.noenc as follows, which has plain name and body text:
msg1:
name: Hello
body: Hello, I am here...
msg2:
name: How are you
body: Good morning, ...
write like the following rake-task (e.g. lib/tasks/encrypt_fixture.rake) to convert messages.yml.noenc to messages.yml:
require 'active_record/fixtures'
src_yml = 'test/fixtures/messages.yml.noenc'
dest_yml = 'test/fixtures/messages.yml'
task 'test' => dest_yml
namespace :[MY_APP] do
desc "generate encrypted fixture"
file dest_yml => src_yml do |t|
require Rails.root + 'config/environment'
encrypted_hash = {}
for k, v in YAML.load(ERB.new(File.read(Rails.root + src_yml)).result) do
msg = Message.new(v.merge([ANY ADDITIONAL ATTRS]))
encrypted_hash[k] = {
'encrypted_name' => msg.encrypted_name,
'encrypted_name_iv' => msg.encrypted_name_iv,
'encrypted_body' => msg.encrypted_body,
'encrypted_body_iv' => msg.encrypted_body_iv,
[ANY ADDITIONAL KEY_N_VALUE]
}
end
File.open(Rails.root + t.name, 'w') do |f|
f.write(<<EOH)
#----------------------------------------------------------------------
# DO NOT MODIFY THIS FILE!!
#
# This file is generated from #{src_yml} by:
#
# (edit #{src_yml})
# $ rake [MY_APP]:generate_fixture, or
# $ rake
#----------------------------------------------------------------------
EOH
f.write(encrypted_hash.to_yaml)
end
end
end
Please substitute [MY_APP], [ANY ADDITIONAL ATTRS], and [ANY ADDITIONAL KEY_N_VALUE] to actual values.
Then, 'rake' or 'rake test' checks file dependency between messages.yml.noenc and messages.yml, and generate messages.yml when necessary before 'rake test'.

REXML::Document.new take a simple string as good doc?

I would like to check if the xml is valid. So, here is my code
require 'rexml/document'
begin
def valid_xml?(xml)
REXML::Document.new(xml)
rescue REXML::ParseException
return nil
end
bad_xml_2=%{aasdasdasd}
if(valid_xml?(bad_xml_2) == nil)
puts("bad xml")
raise "bad xml"
end
puts("good_xml")
rescue Exception => e
puts("exception" + e.message)
end
and it returns good_xml as result. Did I do something wrong? It will return bad_xml if the string is
bad_xml = %{
<tasks>
<pending>
<entry>Grocery Shopping</entry>
<done>
<entry>Dry Cleaning</entry>
</tasks>}
Personally, I'd recommend using Nokogiri, as it's the defacto standard for XML/HTML parsing in Ruby. Using it to parse a malformed document:
require 'nokogiri'
doc = Nokogiri::XML('<xml><foo><bar></xml>')
doc.errors # => [#<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: bar line 1 and xml>, #<Nokogiri::XML::SyntaxError: Premature end of data in tag foo line 1>, #<Nokogiri::XML::SyntaxError: Premature end of data in tag xml line 1>]
If I parse a document that is well-formed:
doc = Nokogiri::XML('<xml><foo/><bar/></xml>')
doc.errors # => []
REXML treats a simple string as a valid XML with no root node:
xml = REXML::Document.new('aasdasdasd')
# => <UNDEFINED> ... </>
It does not however treat illegal XML (with mismatching tags, for example) as a valid XML, and throws an exception.
REXML::Document.new(bad_xml)
# REXML::ParseException: #<REXML::ParseException: Missing end tag for 'done' (got "tasks")
It is missing an end-tag to <done> - so it is not valid.

ActiveRecord::Fixture::FormatError: a YAML error occurred parsing

I 'm trying to make a of my first application on ruby ...
Thats's my test file
require File.dirname(__FILE__) + '/../test_helper'
class SupplierTest < ActiveSupport::TestCase
fixtures :suppliers
def test_name
supplier=Supplier.create(:name => 'juan' , :province => nil)
assert_equal 'juan' , supplier.get_name
end
end
and the fixture
juan:
id:1
name:juan
province:nil
and the result is
Psych::SyntaxError: (<unknown>): could not find expected ':' while scanning a simple key at line 8 column 1
YAML requires a space between the : and the value, so try updating your fixture to:
juan:
id: 1
name: juan
province:
(writing nil in province will result in the value "nil". Leaving it empty will result in a true nil value)

Resources