I am having trouble testing my mailer. It appears assigning attributes [:to, :from, :reply_to] with a email in the format described as email-with-name doesn't work.
Here is a simple example.
class MessageMailer < ActionMailer::Base
def simple
mail(
from: "Aaron Test <aaron#test.com>",
to: "Aaron Test <aaron#test.com>",
reply_to: "Aaron Test <aaron#test.com>"
)
end
end
message_mailer_spec.rb
EXPECTED = "Aaron Test <aaron#test.com>"
describe MessageMailer do
before do
#email = MessageMailer.simple
end
it "expect `from` to eq #{EXPECTED}" do
expect( #email.from ).to eq(EXPECTED)
end
it "expect `to` to eq #{EXPECTED}" do
expect( #email.to ).to eq(EXPECTED)
end
it "expect `reply_to` to eq #{EXPECTED}" do
expect( #email.reply_to ).to eq(EXPECTED)
end
end
Test results all the same
1) MessageMailer expect `reply_to` to eq Aaron Test <aaron#test.com>
Failure/Error: expect( #email.reply_to ).to eq(EXPECTED)
expected: "Aaron Test <aaron#test.com>"
got: ["aaron#test.com"]
(compared using ==)
Anyone know how to assign [to:, from:, reply_to:] in the email-with-name format?
Am I missing something?
Are there different methods that hold the email headers that I can test against?
Ok I got it by testing against the header hash of the email.
This is how to test the values of 'from', 'reply_to' and 'to' in rspec.
describe MessageMailer do
before do
#email = MessageMailer.simple
end
it "expect `from` to be formatted correctly" do
expect( #email.header['From'].to_s ).to eq("Aaron Test <aaron#test.com>")
end
it "expect `reply_to` to be formatted correctly" do
expect( #email.header['Reply-To'].to_s ).to eq("Aaron Test <aaron#test.com>")
end
it "expect `to` to be formatted correctly" do
expect( #email.header['To'].to_s ).to eq("Aaron Test <aaron#test.com>")
end
end
* Update:
The square brackets you're getting indicate that you're receiving an array. So you need to extract the values out of the array to verify their validity. The reason for this is that you could have multiple addressees, so for example the object could return:
["Aaron Test ", "Renoir "]
As far as I understand, you don't need to use the square brackets, and you don't need to include the quote marks in the string.
These should work:
from: "Aaron Test <aaron#test.com>",
reply_to: "Aaron Test <aaron#test.com>"
Related
I have the following validation,
it should match string with letters,numbers,dashes. And empty input should also be valid.
The normal string validation is ok, but I can not make it match "empty" input.
'letter_code' => 'regex:/^[A-Za-z0-9\-]*$/'
letter_code format is invalid
tests:
"C14" // valid
"3.14" // "format is invalid", as expected
"-" // valid
"" // "format is invalid", NOT expected
I just found out in laracasts forum, that there is a nullable rule.
You can read about it in the official docs.
Without the nullable rule empty strings are considered invalid if there is a regex rule as well.
If you don't add required as additional validator empty string must pass
Here is phpunit test:
/** #test */
public function letterCode()
{
$trans = new \Illuminate\Translation\Translator(
new \Illuminate\Translation\ArrayLoader, 'en'
);
$regex = 'regex:/^[A-Za-z0-9\-]*$/';
$v = new Validator($trans, ['x' => 'C14'], ['x' => $regex]);
$this->assertTrue($v->passes());
$v = new Validator($trans, ['x' => '3.14'], ['x' => $regex]);
$this->assertFalse($v->passes());
$v = new Validator($trans, ['x' => '-'], ['x' => $regex]);
$this->assertTrue($v->passes());
$v = new Validator($trans, ['x' => ''], ['x' => $regex]);
$this->assertTrue($v->passes());
}
This is tested with Laravel 5.5
I was facing the same problem in Laravel 7.x using GraphQL Types. I needed something similar to this in a field called phone or nothig (empty string). So I did something like this:
'phone' => [
'name' => 'phone',
'type' => Type::string(),
'rules' => ['regex:/^[A-Za-z0-9\-]*$/','nullable']
Here, phone is the name of the field you want to enter text into, and rules is what we define as regex, or NULL.
Hope this helps someone!
looks like I am losing 'San Francisco' at the start of the Update test in this example - not sure why - when I do a puts response.body at the end the Post Test everything looks ok - here is my flights_spec.rb:
require 'rails_helper'
require 'spec_helper'
require 'flight'
RSpec.describe FlightsController, type: :controller do
render_views
let(:flight0) { Flight.create(:destination => "Las Vegas") }
it "Get Test" do
puts 'Get Test'
get :index, :format => :json
puts "Body = " + response.body
expect(response.body).to include('Las Vegas')
end
it "Post Test" do
puts 'Post Test'
post :create, :flight => {:destination => "San Francisco"}
puts "Post status:" + response.status.to_s
expect(response).to redirect_to(assigns(:flight))
redirect_to(response.headers['Location'])
get :index, :format => :json
puts "Body = " + response.body
expect(response.body).to include("San Francisco")
end
it "Update Test" do
puts 'Delete Test'
get :index, :format => :json
puts "Body = " + response.body
expect(response.body).to include("San Francisco")
end
end
RSpec assumes that you are writing each test to be independent of the other tests. However, the way you have it here, Update Test relies on Post Test to create the data it needs. RSpec automatically undoes any changes you made between each test. You can think of each it block as resetting everything back to the initial state.
A quick fix would be to simply aim the delete at the Las Vegas object instead since this flight is already being recreated for each test because of the let statement:
it "Update Test" do
puts 'Delete Test'
get :index, :format => :json
puts "Body = " + response.body
expect(response.body).to include("Las Vegas")
# rest of your test
end
Also I just would note that you may run into issues with the let statement because it is lazily instantiated, meaning it may not actually create a Las Vegas flight until you actually try to use the flight0 variable in your test. You can fix that by simply adding a bang to the end, like this let!(:flight_0) {}.
I am writing Request specs, and having trouble with to test api respond in json formate. I am using capybara and fabricator, here is my code which i trying...
context 'discounts in api' do
let(:user) { Fabricate(:user, activated: true) }
let(:api_token) { user.api_token }
before { visit api_url_for('/v1/discount_coupons', api_token) }
it 'returns coupons collection' do
Fabricate(:discount_coupon, code: 'Discount One', global: true)
save_screenshot("tmp/capybara/screenshot-#{Time::now.strftime('%Y%m%d%H%M%S%N')}.png")
save_and_open_page
expect(json_response['total_records']).to eq 1
expect(json_response['total_pages']).to eq 1
expect(json_response['page']).to eq 0
expect(json_response['discount_coupons'].size).to eq 1
expect(json_response['discount_coupons'][0]['code']).to eq 'Discount One'
end
end
the responce i getting is this
{"discount_coupons":[{"id":11,"code":"Discount One","type":"DiscountPercentage","amount_off":1.5,"global":true,"expires_on":null,"vendors":[]}],"page":0,"total_pages":1,"total_records":1}
and error goes to stop me for run a successful test,
Failure/Error: expect(json_response['total_pages']).to eq 1
NoMethodError:
undefined method `body' for nil:NilClass
I think my expect to json_response is wrong or something missing, can somone help me to do it handsome way please, hint to that how can i test using key and value.
Best way to test an API is use rspec as you just need to do this:
it "should return the expected information" do
get "/url"
parsed_response = JSON.parse(response.body)
expect(parsed_response["key"]).to eq(whatever)
end
it "should update the expected entity" do
post "/url", body, headers
parsed_response = JSON.parse(response.body)
expect(parsed_response["key"]).to eq(whatever)
end
And your tests are failing because you are trying to parse a response that is empty. The Fabric can be failing or the call might be wrong.
I think the issue may be that you are visiting the page in the before block and then generating the discount coupon later on in the assertion block. Try moving the code around like this and see if it yields a better result.
context 'discounts in api' do
let(:user) { Fabricate(:user, activated: true) }
let(:api_token) { user.api_token }
before do
Fabricate(:discount_coupon, code: 'Discount One', global: true)
visit api_url_for('/v1/discount_coupons', api_token)
end
it 'returns coupons collection' do
save_screenshot("tmp/capybara/screenshot-#{Time::now.strftime('%Y%m%d%H%M%S%N')}.png")
save_and_open_page
expect(json_response['total_records']).to eq 1
expect(json_response['total_pages']).to eq 1
expect(json_response['page']).to eq 0
expect(json_response['discount_coupons'].size).to eq 1
expect(json_response['discount_coupons'][0]['code']).to eq 'Discount One'
end
Background:
I have a custom generated log file that has the following pattern :
[2014-03-02 17:34:20] - 127.0.0.1|ERROR| E:\xampp\htdocs\test.php|123|subject|The error message goes here ; array (
'create' =>
array (
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
),
)
[2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line
The second entry [2014-03-02 17:34:20] - 127.0.0.1|DEBUG| flush_multi_line Is a dummy line, just to let logstash know that the multi line event is over, this line is dropped later on.
My config file is the following :
input {
stdin{}
}
filter{
multiline{
pattern => "^\["
what => "previous"
negate=> true
}
grok{
match => ['message',"\[.+\] - %{IP:ip}\|%{LOGLEVEL:loglevel}"]
}
if [loglevel] == "DEBUG"{ # the event flush line
drop{}
}else if [loglevel] == "ERROR" { # the first line of multievent
grok{
match => ['message',".+\|.+\| %{PATH:file}\|%{NUMBER:line}\|%{WORD:tag}\|%{GREEDYDATA:content}"]
}
}else{ # its a new line (from the multi line event)
mutate{
replace => ["content", "%{content} %{message}"] # Supposing each new line will override the message field
}
}
}
output {
stdout{ debug=>true }
}
The output for content field is : The error message goes here ; array (
Problem:
My problem is that I want to store the rest of the multiline to content field :
The error message goes here ; array (
'create' =>
array (
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
),
)
So i can remove the message field later.
The #message field contains the whole multiline event so I tried the mutate filter, with the replace function on that, but I'm just unable to get it working :( .
I don't understand the Multiline filter's way of working, if someone could shed some light on this, it would be really appreciated.
Thanks,
Abdou.
I went through the source code and found out that :
The multiline filter will cancel all the events that are considered to be a follow up of a pending event, then append that line to the original message field, meaning any filters that are after the multiline filter won't apply in this case
The only event that will ever pass the filter, is one that is considered to be a new one ( something that start with [ in my case )
Here is the working code :
input {
stdin{}
}
filter{
if "|ERROR|" in [message]{ #if this is the 1st message in many lines message
grok{
match => ['message',"\[.+\] - %{IP:ip}\|%{LOGLEVEL:loglevel}\| %{PATH:file}\|%{NUMBER:line}\|%{WORD:tag}\|%{GREEDYDATA:content}"]
}
mutate {
replace => [ "message", "%{content}" ] #replace the message field with the content field ( so it auto append later in it )
remove_field => ["content"] # we no longer need this field
}
}
multiline{ #Nothing will pass this filter unless it is a new event ( new [2014-03-02 1.... )
pattern => "^\["
what => "previous"
negate=> true
}
if "|DEBUG| flush_multi_line" in [message]{
drop{} # We don't need the dummy line so drop it
}
}
output {
stdout{ debug=>true }
}
Cheers,
Abdou
grok and multiline handling is mentioned in this issue https://logstash.jira.com/browse/LOGSTASH-509
Simply add "(?m)" in front of your grok regex and you won't need mutation. Example from issue:
pattern => "(?m)<%{POSINT:syslog_pri}>(?:%{SPACE})%{GREEDYDATA:message_remainder}"
The multiline filter will add the "\n" to the message. For example:
"[2014-03-02 17:34:20] - 127.0.0.1|ERROR| E:\\xampp\\htdocs\\test.php|123|subject|The error message goes here ; array (\n 'create' => \n array (\n 'key1' => 'value1',\n 'key2' => 'value2',\n 'key3' => 'value3'\n ),\n)"
However, the grok filter can't parse the "\n". Therefore you need to substitute the \n to another character, says, blank space.
mutate {
gsub => ['message', "\n", " "]
}
Then, grok pattern can parse the message. For example:
"content" => "The error message goes here ; array ( 'create' => array ( 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3' ), )"
Isn't the issue simply the ordering of the filters. Order is very important to log stash. You don't need another line to indicate that you've finished outputting multiline log line. Just ensure multiline filter appears first before the grok (see below)
P.s. I've managed to parse a multiline log line fine where xml was appended to end of log line and it spanned multiple lines and still I got a nice clean xml object into my content equivalent variable (named xmlrequest below). Before you say anything about logging xml in logs... I know... its not ideal... but that's for another debate :)):
filter {
multiline{
pattern => "^\["
what => "previous"
negate=> true
}
mutate {
gsub => ['message', "\n", " "]
}
mutate {
gsub => ['message', "\r", " "]
}
grok{
match => ['message',"\[%{WORD:ONE}\] \[%{WORD:TWO}\] \[%{WORD:THREE}\] %{GREEDYDATA:xmlrequest}"]
}
xml {
source => xmlrequest
remove_field => xmlrequest
target => "request"
}
}
I have a unit test that is failing and I know why but I'm not sure how I should be handling it. I have the following unit test:
new PersistenceSpecification<OrderLine>(session)
.CheckProperty(x => x.Line, "1")
.VerifyTheMappings();
It is failing with the following error:
Test method CanCorrectlyMapOrderLine threw exception:
System.ApplicationException: For property 'Line' expected '1' of type 'System.String' but got '1 ' of type 'System.String'
The reason it's doing this is because x.Line points to a fixed length character field in the database (nchar(10) to be exact) and when it inserts the data it pads it with spaces. Should I be specifying "1" with 9 spaces at the end in my unit tests or should I be trimming this somehow when I read it in? Is there another way to handle this?
I ended up just doing the following with this:
new PersistenceSpecification<OrderLine>(session)
.CheckProperty(x => x.Line, "1".PadRight(10, ' '))
.VerifyTheMappings();