I would like to access the seeded database during the test
my setup:
my seeds for the test contain:
FactoryBot.create_list(:user, 10)
my User factory looks like:
factory :user { email { Faker::Internet.unique.email } }
(so there is no way for me to know their email addresses beforehands)
my goal
at one point in my tests I would love to do something like:
cy.get('body')
.should('contain', `${user.last.email}`)
is there a way to achieve that result inside a Cypress test?
The Cypress Real World App, a payment application to demonstrate real-world usage of Cypress testing methods, patterns, and workflows, demonstrates how to access seeded data via a remote command implemented in a way that is language and framework agnostic.
It is done using a Cypress Command, cy.database, which calls a Cypress Task depending upon the operation (filter or find).
The tasks issue an API request to a test API endpoint which is only exposed for the test environment.
This technique can be used to access seed data from a remote or local instance, and can be used to drive tests, as demonstrated in the notifications spec.
You could use the https://github.com/shakacode/cypress-on-rails gem to get this working.
After setting up the gem your code could look like this:
cy.appFactories([
['create_list', 'user', 9],
['create', 'user', email: 'myuser#email.com'],
])
cy.visit('/users')
cy.get('body').should('contain', 'myuser#email.com')
Related
For context, this question arose because we are migration from Rails 5 to Rails 6, and introducing reader / writer database connections via the new replication features.
Our specific problem is with request specs, with an eye towards using transactional fixtures. When we run our request specs files in isolation, they pass. When run as part of a multiple-file pass (such as a full bundle exec parallel_rspec pass used on circle CI) they fail. If we turn off transactional fixtures, the tests take far too long to run, but pass.
Using byebug, we've poked in and determined that the problem is that our test data has been written to / is accessible by the writer DB connection, but the route is attempting to use the reader DB connection to read it. I. E. ActiveRecord::Base.connected_to(role: :reading) { puts Foo.count } is 0, while the same code connecting to writing role is non-zero.
The problem from there seems fairly obvious: because we're using transactional tests / fixtures, the code is never committed to the DB. It's only available on the connection it was made on. The request spec is reading from the 'right' db for the call (a GET request should use the reader db), but in the use-case of tests that's producing errors.
It seems like this is a fairly obvious use case that either Rails or rspec should have a tool for handling, we just don't seem to be able to find the relevant documentation.
You need to tell the test environment that it should be using a single connection for both. There are multiple ways of doing this:
You can configure your test environment not to use replicas at all. See Setting up your application for examples of using a replica and not using a replica then reproduce the non-replica version in your database.yml for the test environment only.
You can use connected_to within your specs themselves so that those tests are forced to use the specific connection you want them to use. One way to do this is with around hooks:
describe "around filter" do
around(:each) do |example|
puts "around each before"
ActiveRecord::Base.connected_to(role: :writing) { example.run }
puts "around each after"
end
it "gets run in order" do
puts "in the example"
end
end
You can monkey patch your ActiveRecord configuration in rails_helper so that it doesn't use replicas (but I'd really recommend #1 over this option)
Background: I am unit testing a game server which is built upon rails 4.1.1 and separate socket.io/node.js for socket messaging. Messages from node.js to rails are going through RESTful http requests.
Single test case runs as follows:
(1) rake unit test --> (2) rails controller --> (3) node.js/socket.io --> (4) rails controller
Problem description: Some DB entries are created with ActiveRecord at step (2), then upon receiving a socket message at step (3) node.js sends HTTP request back to rails controller and finally(!!) at step (4) rails controller tries to access DB entries from step (2), but TEST DB contents are empty at this point.
Question: It seems like desired behavior of rake to cleanup TEST DB, but how can I persist TEST db across test cases and prevent such problem?
Thanks in advance
You should prepare and send request to node app inside a test and assert response there.
But it's not a good practice. The better solution would be HTTP mocks (like webmock gem). This approach will save lots of time in the future.
Luckily, I figured out the solution.
By default, rake is wrapping all tests in separate DB transactions and rolls back on cleanup. Moreover, whatever requests/queries are coming outside of TestCase are not included in transaction and not visible inside the test case.
To avoid such behavior, we have to disable transactional fixtures in test/test_helper.rb
class ActiveSupport::TestCase
self.use_transactional_fixtures = false
end
As downside, we have to cleanup test db manually. So #Alexander Shlenchack points out to avoid such practice in the first place and use http/socket mocks in future.
Here is brief summary http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
And related question Rails minitest, database cleaner how to turn use_transactional_fixtures = false
I want to test my Ruby-on-Rails website that uses PostgreSQL database with Cucumber.
I also have the FactoryGirl gem installed, so I can create factories.
I understand that the typical way to create data for the test database would be to write Gherkin tables and put them in the background block of a cucumber file. But I already have a Ruby script that creates samle data suitable for the test database.
Yet, I am currently lost in Cucumber’s settings. Could you please advise how to make Cucumber run my Ruby script populating the test database before each test and how to clean the test database after each test. Apparently, my google-fu is inadequate for this task.
Just:
add the cucumber rule like I have 4 clock in the pocket to features/clock.feature (for example).
implement the rule in the features/step_definition/clock_steps.rb (for example) to create defined amount Clock models, and single Pocket model. and associate them:
When /I have (\d+) clock in the pocket/ do |amount|
pocket = FactoryGirl.create :pocket
amount.times { FactoryGirl.create :clock, pocket: pocket }
end
So, you then will get some data populated.
If you want predefine the step for most scenarios you can either:
Create a larger step (for example) called I have basic clock setup, then define it as an above one, but add another required steps into it.
or
Use step recursion (this is non-recommended way) as follows:
When /I have basic clock setup/ do |amount|
step 'I have 4 clock in the pocket'
end
I ended up using a Before do block in the .rb file with Cucumber tests:
Before do
<code to populate the test database here>
end
Given /first condition/
do some stuff
end
...and so on
So, i'm building a small application using Rails. I need to use XMPP proto for notification of users with a bit of commands to change user status.
Previous version was an application using plain Python(pretty ugly app) with plain SQL request into DB. There was a table "jabber_queue", so in separated script, bot was checking each second for any rows, processing it(sending message), deleting. It was simple and stupid, but it was ok.
Now i see, i need to integrate this bot functionality into Rails(at least to work with RSpec).
This is my few versions of how it can be done:
Use separated async queue solution. For example, Resque. Use separated Ruby script and push events into Resque, pop events in application(not dependent on DB, so easily fit with RSpec tests and test DB). But it makes my application a bit bloated - i need to use second DB with a lot of memory and CPU additional requirements - it will be overhead for my problem. Also, i don't want to support additional "thing" for this application, i know, it can be done a lot easier way.
Use delayed_job(queue solution using current AR DB). But i don't know how to get current AR DB of Rails application in separated script. Anyway, it's a dirty and ugly way.
Launch XMPP bot WITHIN Rails application, as background worker. So worker will get access to "current" AR(in case of testing, to test-DB). But i simply don't know how to do it. I've found a Navvy, but i need to put somewhere at Rails start a string like a "Navvy::Job.enqueue(Cow, :speak)", i don't know where will be best place for this, to start it with RSpec testing and "rails server". Also, there is a BackgrounDRb, but this project is similar to Navvy and inactive too. Using search on stackoverflow, i've found similar problem to mine, but solution leads me to background_job, which can just anything in background, but i still don't know how to get current AR DB access in separated script.
I'm so sorry for this amount of words in my problem, it's just a brainstream. I see some solutions, but i really need advices and some words from more experienced developers.
So, this was solved using yes, third way.
I've created a class for dealing with bot commands and AR models - awesomo.rb. Nothing special, really. I put this in /lib/ of Rails project. Secondly,
Created configuration file for easy setting of password and JID - config/awesomo.yml
development:
xmpp_jid: ...
xmpp_password: ...
I've created a daemon for my bot - awesomo_daemon.rb. Same, in /lib/. This is what it contains:
#preload rails environment
require File.expand_path(File.join(File.dirname(__FILE__),
'..', 'config', 'environment'))
#load xmpp bot class
require 'awesomo_daemon'
#load xmpp bot configuration file for current environment
AWESOMO_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__),
'..', 'config', 'awesomo.yml'))[Rails.env]
#apply configuration before singleton will be initiated
Awesomo.setup AWESOMO_CONFIG['xmpp_jid'], AWESOMO_CONFIG['xmpp_password']
loop {
Awesomo.instance.idle
sleep 1
}
Created daemon script starter- script/awesomo.
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
Daemons.run "lib/awesomo_daemon.rb", dir_mode: :normal,
dir: File.join(File.dirname(__FILE__), '..', 'tmp', 'pids')
Simply run it with command script/awesomo start.
And I can use any my models within awesomo.rb! Also, for queue, i'm using little model - XMPPJob with fields jtype(for example, "xmpp_message"), body("hey!"), to("john#jabber.com"). Fetching it within awesomo.rb idle function of bot class with limit(5).each do |job| case jtype ....
To post any new job for my "awesomo", i'm using function send_message:
def self.send_message to, body
xmppjob = XmppJob.new :jtype => "xmpp_message", :body => body, :to => to
xmppjob.save
end
Everything works perfectly, except XMPP library(xmpp4r-simple) itself, but I'll rewrite it soon using just xmpp4r.
I'm new to Ruby On Rails. I love, it has Testing capabilities built in. But, I can't wrap around my head with testing. Here is my first basic Question about it.
What happens during testing really?
I understand development, we want some result, we use the data we have or get it from users to achieve the end result we want. But, the notion of testing seems sometimes confusing for me. I have been testing applications in browser for some time, are we replicating the same with code? Is it what testing is about? Replicating browser testing with automated code? Enlighten Me here.
Reading A Guide to Testing Rails Applications will be a good starting point.
Basically, you have three kinds of tests: unit, functional and integration.
Unit tests are testing your Models. In these tests you check whether a single method of your model works as expected, for example you set assign a login with spaces, and then you test whether the spaces were removed:
class UserTest < ActiveSupport::TestCase
def test_login_cleaning
u = User.new
u.login = " login_with_spaces "
assert_equal "login_with_spaces", u.login
end
# ... and other tests
end
Functional tests are testing your controllers (and views). In each test you simulate one request sent to one controller with given set of parameters, and then you ensure that the controller returned the proper response.
Note however, that in this test you cannot test the rendering of the page, so it's not strictly simulating a browser. To test whether your page looks nicely, you need to do it manually (I am almost sure some techniques exist, but I do not know of them).
An example of functional test:
class UserControllerTest < ActionController::TestCase
def test_show_renders_admin
get :show, :id => 1
assert_response :success
assert_select "div.user" do
assert_select "span.name", "Joe Admin"
end
end
def test_show_handles_unknown_id
get :show, :id => 9999
assert_response 404
assert_select "p.warning", "No such user"
end
end
Integration tests are testing a sequence of requests - something like a scenario, where an user logins, gets the 'create user' page, creates an user, and so on. These tests check whether the single requests (tested in functional tests) are able to work together.
I see that Simone already pointed the importance of automation in tests, so the link to the Guide is the only value in my answer ;-)
You may find it very helpful to apply some rules of Test Driven Development, especially when your project matures a little.
I know that it's not easy to start the project by writing test, because often you do not yet know how everything will work, but later, when you find a bug, I strongly suggest to start fixing every bug from writing a failing test case. It really, really helps both in the bug-fixing phase, and later - ensuring that the bug does not reappear.
Well, I noticed that I did not directly answer your question ;-)
When you start test procedure, Rails:
deletes the test database (so make sure you do not have any valuable data here),
recreates it using the structure of the development database (so, make sure you have run all your migrations),
loads all the fixtures (from test/fixtures/*)
loads all the test classes from test/units/* and other directories,
calls every method whose name starts with 'test_' or was created by the macro test "should something.." (alphabetically, but you may consider the order as being random)
before every call it executes a special setup procedure, and after every call it executes teardown procedure,
before every call it may (depending on the configuration) recreate your database data, loading the fixtures again.
You will find more information in the Guide.
What happens during testing is that you really run a set of specialized programs or routines (test code) that calls routines in your application (code under test) and verifies that they produce the expected results. The testing framework usually has some mechanism to make sure that each test routine is independent of the other tests. In other words the result from one test does not affect the result of the others.
In Rails specifically you run the tests using the rake test command line tool. This will load and execute each test routine in a random order, and tell you if each test was successful or not.
This answer doesn't necessary apply to Rails itself. When you talk about testing in Rails, you usually mean automatic testing.
The word automatic is the essence of the meaning. This is in fact the biggest difference between unit testing and "browser" testing.
With unit testing you essentially write a code, a routine, that stresses a specific portion of your code to make sure it works as expected. The main advantages of unit testing compared to "browser" testing are:
It's automatic and can be run programmatically.
Your test suite increases during the development lifecycle.
You reduce the risk of regression bugs, because when you modify a piece of code and you run the test suite, you are actually running all the tests, not just a random check.
Here's a basic, very simple example. Take a model, let's say the User model. You have the following attributes: first_name, last_name. You want a method called name to return the first and last name, if they exist.
Here's the method
class User
def name
[first_name, last_name].reject(&:blank?).join(" ")
end
end
and here's the corresponding unit test.
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def test_name
assert_equal "John Doe", User.new(:first_name => "John", :last_name => "Doe").name
assert_equal "John", User.new(:first_name => "John").name
assert_equal "Doe", User.new(:last_name => "Doe").name
assert_equal "", User.new().name
end
end