I am building a rails application using ActionController::Live and and Custom SSE library,
My server is puma, and rails version is 4 this is my code in my controller:
include ActionController::Live
def index
response.headers['Content-Type'] = 'text/event-stream'
ss = Reloader::SSE.new(response.stream)
100.times {
ss.write({ :message => "just checking"}, :event => 'refresh')
sleep 10
}
ensure
ss.close
end
and this is my Library sse.rb file
class SSE
def initialize io
#io = io
end
def write object, options = {}
options.each do |k,v|
#io.write "#{k}: #{v}\n"
end
#io.write "data: #{JSON.dump(object)}\n\n"
end
def close
#io.close
end
end
and this is my application.js file to handle SSE
$(document).ready(function() {
setTimeout(function() {
var source = new EventSource('/');
source.addEventListener('refresh', function(e) {
window.location.reload();
});
}, 1);
});
I am following the tutorial from this site http://tenderlovemaking.com/2012/07/30/is-it-live.html
Whenever I load my Firefox page, it is not handling the stream, instead it is showing the option to download the stream as text file. I don't why this is happening.
My understanding here of the SSE is at fault here, the SSE and the page/controller i am working, i took them as one, i was trying to view the controller of SSE in firefox or chrome. Very poor understanding on my part of the SSE. SSE controller and the page i want to trigger events are completely different. I got this answer at the end of this tutorial
http://tenderlovemaking.com/2012/07/30/is-it-live.html
Hope you guys got it too.
Related
Here is the issue that has been nagging for weeks and all solutions found online do not seem to work... ie. wait for ajax, etc...
here is versions of gems:
capybara (2.10.1, 2.7.1)
selenium-webdriver (3.0.1, 3.0.0)
rspec (3.5.0)
running ruby 2.2.5
ruby 2.2.5p319 (2016-04-26 revision 54774) [x64-mingw32]
in the env.rb
Capybara.register_driver :selenium do | app |
browser = (ENV['browser'] || 'firefox').to_sym
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
Capybara.default_max_wait_time = 5
end
Here is my dynamicpage.feature
Given I visit page X
Then placeholder text appears
And the placeholder text is replaced by the content provided by the json service
and the step.rb
When(/^I visit page X$/) do
visit('mysite.com/productx/')
end
When(/^placeholder text appears$/) do
expect(page).to have_css(".text-replacer-pending")
end
Then(/^the placeholder text is replaced by the content provided by the json service$/) do
expect(page).to have_css(".text-replacer-done")
end
the webpage in question, which I cannot add it here as it is not publicly accessible, contains the following on page load:
1- <span class="text-replacer-pending">Placeholder Text</span>
after a call to an external service (which provides the Json data), the same span class gets refreshed/updated to the following;
2- <span class="text-replacer-done">Correct Data</span>
The problem I have with the "visit" method in capybara + selenium is that as soon as it visits the page, it thinks everything loaded and freezes the browser, and it never lets the service be called to dynamically update the content.
I tried the following solutions but without success:
Capybara.default_max_wait_time = 5
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
add sleep 5 after the visit method
wait for ajax solution from several websites, etc...
adding after hooks
etc...
I am at a complete loss why "visit" can't wait or at least provide a simple solution to an issue i am sure is very common.
I am aware of the capybara methods that wait and those that don't wait such as 'visit' but the issue is;
there is no content that goes from hidden to displayed
there is there is no user interaction either, just the content is getting updated.
also unsure if this is a capybara issue or a selenium or both.
Anyhow have insight on any solutions? i am fairly new to ruby and cucumber so specifically what code goes in what file/folder would be much appreciated.
Mel
Restore wait_until method (add it to your spec_helpers.rb)
def wait_until(timeout = DEFAULT_WAIT_TIME)
Timeout.timeout(timeout) do
sleep(0.1) until value = yield
value
end
end
And then:
# time in seconds
wait_until(20) { has_no_css?('.text-replacer-pending') }
expect(page).to have_css(".text-replacer-done")
#maxple and #nattf0dd
Just to close the loop on our issue here...
After looking at this problem from a different angle,
we finally found out Cucumber/Capybara/ is not a problem at all :-)
The issue we are having lies with the browser Firefox driver (SSL related), since we have no issues when running the same test with the Chrome driver.
I do appreciate the replies and suggestions and will keep those in mind for future.
thanks again!
I have one factory with inheritance
FactoryGirl.define do
factory :client do
sequence(:first_name) { |n| "John#{n}" }
sequence(:last_name) { |n| "Smith#{n}" }
factory : client_with_dialog do
show_popup true
end
On my react code I am getting from the server the client show popup value.
$.get('/client/get_choise')
.done(function (result) {
if (result.show_popup) {
alert();
}
});
test code:
scenario 'visit page with popup' do
client = create :client_with_dialog
visit_page_with_popup
end
On my capybara testing the popup is not showing,
My question is does the $.get('/client/get_choise') code actually run in tests or not?
How can I write a capybara test that will actually open the popup window?
It sounds like you're using the rack-test driver which doesn't support JavaScript. Start here https://github.com/jnicklas/capybara#selecting-the-driver
Here's some background first.
My aim is to use Ratchet WebSockets to create two-way client-server communication.
I have installed ratchet and accompanying software, as described here.
I have successfully created a Hello World application as described here.
Now I am trying to create Push functionality using this tutorial. I have copied the code, modifying it slightly (modifications noted in code comments below), installed the ZMQ library (latest version, added it to php.ini, show up in php -m - in short, it's installed correctly). But the WebSockets don't work.
I will give my testing process with real live links to my domain below, so you can check it yourself.
My push server is exactly the same as the one in their tutorial, with the IP changed to my server's IP. I run this through SSH and it seems to connect correctly.
My Pusher class is in the MyApp namespace, same code and same relative location as in their tutorial.
My post.php is slightly modified because there's no need to bother with MySQL queries:
$entryData = array( //hard-coded content of $entryData for simplicity
'cat' => "macka"
, 'title' => "naslov"
, 'article' => "tekst"
, 'when' => time()
);
// This is our new stuff
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://light-speed-games.com:5555"); //my domain, still using port 5555 as in their example
$socket->send(json_encode($entryData));
This file is located here.
My client.php is the same as theirs, except I had to add a little fix for IE to work with when.js. My problem is browser-independent and the same as it was before the fix was added.
<script>
window.define = function(factory) { //my addition
try{ delete window.define; } catch(e){ window.define = void 0; } // IE
window.when = factory();
};
window.define.amd = {};
</script>
<script src="/apps/scripts/when.js"></script>
<script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js"></script>
<script>
var conn = new ab.Session(
'ws://light-speed-games.com:8080' // The host (our Ratchet WebSocket server) to connect to
, function() { // Once the connection has been established
conn.subscribe('kittensCategory', function(topic, data) {
// This is where you would add the new article to the DOM (beyond the scope of this tutorial)
console.log('New article published to category "' + topic + '" : ' + data.title);
});
}
, function() { // When the connection is closed
console.warn('WebSocket connection closed');
}
, { // Additional parameters, we're ignoring the WAMP sub-protocol for older browsers
'skipSubprotocolCheck': true
}
);
</script>
This file is located here.
In theory, what should happen is this (for example): I open client.php in Chrome with console switched on; then I open post.php in Firefox; Chrome's console should show the message 'New article published...' etc (from the conn.subscribe function in client.php). However, when I do this, nothing happens. The connection remains open (doesn't show the 'connection closed' error until I switch off push-server.php through SSH). The console remains empty.
I think that's all the relevant info from the last couple of days, a large portion of which I've spent on trying to figure this out. However, I've been unable to even make sure if the problem is with the code or with some server configuration setting I may be unaware of. So, I come to you hoping someone will point me in the right direction.
Important edit
I'm pretty sure the problem is with the Autobahn.js method conn.subscribe not working properly. The connection is being established. When I change the code to:
function() { // Once the connection has been established
console.log('Connection established');
conn.subscribe('kittensCategory', function(topic, data) {
// This is where you would add the new article to the DOM (beyond the scope of this tutorial)
console.log('New article published to category "' + topic + '" : ' + data.title);
});
}
Then Connection established is shown in the console correctly. So I believe we need to troubleshoot the subscribe method. If someone can explain to me how it works, and what exactly "topic" and "data" are supposed to be, it would be of great help. The Autobahn documentation uses a URL as an argument for this method (see here).
Your client is looking for an article in kittensCategory, but you are sending category macka. Try this:
$entryData = array(
'cat' => "kittensCategory",
'title' => "naslov",
'article' => "tekst",
'when' => time()
);
Is it correct to see your host light-speed-games.com on port 8080 is not functioning? If not, I would suggest to fix this as it is likely its causing your issues.
I'm trying to implement basic Rails 4 code with Event Wource API & Action controller live. Everything is fine but I'm not able to reach event listener.
Controller code:
class HomeController < ApplicationController
include ActionController::Live
def tester
response.headers["Content-Type"] = "text/event-stream"
3.times do |n|
response.stream.write "message: hellow world! \n\n"
sleep 2
end
end
Js code:
var evSource = new EventSource("/home/tester");
evSource.onopen = function (e) {
console.log("OPEN state \n"+e.data);
};
evSource.addEventListener('message',function(e){
console.log("EventListener .. code..");
},false);
evSource.onerror = function (e) {
console.log("Error State \n\n"+e.data);
};
When I reload the page, my console output was "OPEN state" & then "Error State". Event listener code was not displaying.
When I'm curling the page, "message: Hellow world!" was displaying.
I changed in development.rb
config.cache_classes = true
config.eager_load = true
My browsers are chrome & firefox are latest versions, so no issues with them
Where I'm missing? suggestions please!
Event format for server-sent events is
"data: message text\n\n"
So, in your case it should be like:
response.stream.write "data: hello world! \n\n"
Check this MDN page for reference.
I'm new to Capybara and testing on Rails in general, so please forgive me if this is a simple answer.
I've got this test
it "should be able to edit an assignment" do
visit dashboard_path
select(#project.client + " - " + #project.name, :from => "assignment_project_id")
select(#team_member.first_name + " " + #team_member.last_name, :from => "assignment_person_id")
click_button "Create assignment"
page.should have_content(#team_member.first_name)
end
it passes as is, but if I add :js => true it fails with
cannot select option, no option with text 'Test client - Test project' in select box 'assignment_project_id'
I'm using FactoryGirl to create the data, and as the test passes without JS, I know that part is working.
I've tried with the default JS driver, and with the :webkit driver (with capybara-webkit installed)
I guess I don't understand enough what turning on JS for Capybara is doing.
Why would the test fail with JS on?
I've read the Capybara readme at https://github.com/jnicklas/capybara and it solved my issue.
Transactional fixtures only work in the default Rack::Test driver, but
not for other drivers like Selenium. Cucumber takes care of this
automatically, but with Test::Unit or RSpec, you may have to use the
database_cleaner gem. See this explanation (and code for solution 2
and solution 3) for details.
But basically its a threading issue that involves Capybara having its own thread when running the non-Rack driver, that makes the transactional fixtures feature to use a second connection in another context. So the driver thread is never in the same context of the running rspec.
Luckily this can be easily solve (at least it solved for me) doing a dynamic switching in th DatabaseCleaner strategy to use:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :each do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
config.after do
DatabaseCleaner.clean
end
end
A variation of brutuscat's answer that fixed our feature specs (which all use Capybara):
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
# set the default
DatabaseCleaner.strategy = :transaction
end
config.before(:each, type: :feature) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
There is another way to deal with this problem now described and discussed here: Why not use shared ActiveRecord connections for Rspec + Selenium?