Whats the best way to integration test a facebook application? - ruby-on-rails-3

So, I have a facebook App that I am testing. I'd like to test a user's interaction on the app, and I'm having an issue.
The user flow that I'm testing is relatively simple: when a user comes to the in-page facebook app, if they already like the page in which the app is located they will see x-content, if they have not yet liked the page, they will be met with a like gate. My goal is to confirm that my users are able to see certain text once they have like the facebook page.
my test:
describe "facebook" do
it "visit and like page", :vcr do
Capybara.current_driver = :selenium
visit "https://www.facebook.com/pages/Testpage/433439410073990?id=433439410073990&sk=app_454512097948559"
within('#login_form') do
fill_in "email", with: FB_EMAIL
fill_in "pass", with: FB_PASSWORD
click_on "Log In"
end
page.should have_content('Testpage')
within('#timelineHeadlineLikeButton') do
click_on 'like'
end
end
end
my problem is that I can't figure out how to get capybara to like the page.
How are you integration testing you facebook applications?

I don't have the complete example.
test.rb
(You can add it to a initializer and add it if the enviroment is test).
OmniAuth.config.test_mode = true
FACEBOOK_INFO = {
"id"=> "220449",
"email" => "nypee#facebook.com",
}
OmniAuth.config.mock_auth[:facebook] = {
"uid" => '112345',
"provider" => 'facebook',
"user_info" => {"name" => "Nype Aylor", "nickname" => 'Aylor'},
"credentials" => {"token" => 'plataformatec'},
"extra" => {"user_hash" => FACEBOOK_INFO}
}
This simulates the call to omniauth.
So in your test, when you simulate a click to the facebook button,
the response you will get is the one from
OmniAuth.config.mock_auth[:facebook].
I think is the best way to integrate testing with Facebook

Related

After a successful login, I want to be redirected to the screen I was on before I logged in. getLoginRedirect() does not work

Suppose you were in the user list screen. From there you will go to the login screen to log in. There, you will enter your email and password and enter the submit button.
You have successfully logged in.
If the login is successful, we want to be redirected to the user list screen.
If you were in the user details screen, you will be redirected to the user details screen by
If the user was on the edit screen, the user editing screen
I have read the AuthenticationPlugin documentation at book.cakephp.org.
There I learned to use getLoginRedirect() to achieve this functionality.
I am aware that what I want to do will happen once I set up in the steps below.
However, getLoginRedirect() returns null.
What do I need to do?
What am I missing?
What's wrong?
// in Application.php
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$path = $request->getPath();
$authenticationService = new AuthenticationService([
'unauthenticatedRedirect' => '/',
'queryParam' => 'redirect', // <- I believe this is the only one that matters.
]);
// Abbreviated below....
}
// in UsersController
public function login()
{
$this->request->allowMethod(['get', 'post']);
if ($this->request->is('post')) {
$result = $this->Authentication->getResult();
$requestData = $this->request->getData();
if ($result->isValid()) {
// I want to get the original url. But null is passed.
$redirect = $this->Authentication->getLoginRedirect() ?? '/';
return $this->redirect($redirect);
}
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error(__('メールアドレス、またはパスワードが間違っています。'));
}
}
}
I think I've disclosed everything related to getLoginRedirect(). If there is something missing or something you are curious about, please feel free to let me know.
Please help me. Please help me...
The login redirect functionality provided by the plugin only works automatically when you are being redirected to the login URL after accessing a URL that requires authentication while not being logged in. In that case the authentication middleware will set the redirect query string variable with the current URL, so that the component can pick it up after the redirect to the login URL.
If you manually visit the login URL, then you'd also need to manually set the redirect query string variable, ie in your menu where you build the link that takes you to the login, add the current URL to the query string, something along the lines of this:
$service = $this->request->getAttribute('authentication');
// here `$queryParam` would by default be `redirect`
$queryParam = $service->getConfig('queryParam');
echo $this->Html->link('Login', [
'plugin' => null,
'prefix' => false,
'controller' => 'Users',
'action' => 'login',
'?' => [
$queryParam => $this->request->getRequestTarget(),
],
]);
So if you're on /users/show, the login link's URL would look something like:
/login?redirect=/users/show
and the form helper that builds your login form should pick up that exact URL, so that after submitting the form, the authentication component can read the redirect URL from the current URL accordingly.
See also
Cookbook > Views > Helpers > Html > Creating Links

How to get capybara chrome headless to open sweetalert2 modals for Rspec tests

I'm currently using
selenium-webdriver 3.141.0
chromedriver-helper 2.1.0
gem 'rails-assets-sweetalert2', source: 'https://rails-assets.org'
gem 'sweet-alert2-rails'
With Rails 5.2
My Capybara setup:
RSpec.configure do |config|
config.before(:each, type: :system) do
driven_by :rack_test
end
config.before(:each, type: :system, js: true) do
driven_by :selenium_chrome_headless
end
end
require "capybara-screenshot/rspec"
#Use the following to set the screen size for tests
Capybara.register_driver :selenium_chrome_headless do |app|
options = Selenium::WebDriver::Chrome::Options.new
[
"headless",
"window-size=1280x1280",
"disable-gpu" # https://developers.google.com/web/updates/2017/04/headless-chrome
].each { |arg| options.add_argument(arg) }
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
I run the following test:
require 'rails_helper'
RSpec.describe 'deleting a proofread document using ajax', js: true do
let(:job) { create(:proofreading_job, title: 'Internal Job') }
let(:user) { job.proofreader.user }
it 'can delete a proofread document' do
visit root_path
click_on 'Login'
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
click_on 'Sign In'
click_on 'Dashboard'
click_on 'Proofreading Jobs'
click_on 'Current'
click_on 'Internal Job'
click_on 'Upload Proofread Document'
attach_file(I18n.t('proofreader.proofread_document.upload'), Rails.root + 'spec/test_documents/proofread_document/1.docx' , make_visible: true)
accept_alert do
find_button('Upload', disabled: false).click
end
expect(page).to_not have_button('Delete')
end
end
end
However the test fails with Rspec informing me that:
Capybara::ModalNotFound:
Unable to find modal dialog
However, I have manually used the webpage and the modal does show and work properly.
How can I get Capybara Selenium Chrome Headless Driver to open the modal in the tests?
accept_alert is for dealing with system modals (those the browser creates by default when calling window.alert that don't actually add elements to the page). Sweetalert2 is a JS library that inserts elements to the page to create more stylish "modals". You don't use accept_alert with those, you just interact with them as if they were any other HTML elements on the page. That would mean something along the lines of
....
attach_file(...)
click_button('Upload', disabled: false) # Not sure why you're passing `disabled: false` here since that's the default
within('.swal2-actions') { click_button('the text of the button to accept the "modal"') }
expect(page)....
Update: As discovered in the comments - an additional cause of this issue was the assets not being compiled, in the OPs setup, so the JS wasn't firing at all. This would be immediately clear when running in non-headless mode and seeing that no "modal" was ever being displayed. The fix for that depends on what asset pipeline is being used and how it's configured, which goes beyond the scope of this question.

Captive portal login with facebook Safari pop up window

I've built a captive portal for some routers I've configured with a Radius server, so when a customer tries to login, they're faced with a login screen (think McDonalds situation)... Facebook being one of the options to login with.
This all works on Google Chrome, the problem is with Safari.
Safari on Mac or iPhone I've learnt tries to reach http://www.apple.com/library/test/success.html and if it doesn't return the word "success" Apple/Safari then knows it's a captive portal situation so tries to help out by popping up a (Safari) window where you can login.
My problem is that Facebook has some popup's of it's own, and these aren't working in Safari's popup window (they work through Safari's main browser):
If you're not logged in, Facebook will popup a login to Facebook window.
If you are logged in with Facebook, but the App is not authorised, a pop up will show asking you to click OK and check permissions to authorise.
I've overcome point 1, by instead redirecting the user to the Facebook login window that can return back to my website, but I've not overcome point 2.
Here's how I've overcome point 1.
FB.getLoginStatus(function(response) {
//statusChangeCallback(response);
var uri = encodeURI('MY WEBSITE');
if (response.status === 'connected') {
location.reload();
} else if(response.status === 'unknown') {
window.location = encodeURI("https://www.facebook.com/dialog/oauth?client_id=1543071895971445&redirect_uri="+uri+"&response_type=token");
} else {
//can't avoid the Facebook 'authorise app' popup that doesn't work on Apple captive portal popup.
FBSignup();
}
In the else statement above, FBSignup() calls the FB.login function that brings up the authorise popup.
Is there a way I can overcome point 2 by presenting the user with a method to authorise the app without a popup? I'm also using the Facebook PHP SDK if something there can help?
Alternatively accepted answer would be to help me resolve why I the Facebook popups don't work in the captive portal assistant that apple brings up.
I solved this by using the PHP v5.0 SDK to instead generate a Facebook URL to redirect the user to, which doesn't bring any popups, so is Apple captive-portal friendly. You can also request permissions through this redirect, here's how.
$fb = new Facebook\Facebook([
'app_id' => fbappid,
'app_secret' => fbappsecret,
'default_graph_version' => 'v2.2',
]);
$helper = $fb->getRedirectLoginHelper();
$permissions = ['email', 'user_birthday', 'user_location', 'user_hometown', 'user_relationships']; // Optional permissions
$loginUrl = $helper->getLoginUrl('http://localhost/urbanportal/wifilogin.php?origlink='.$_SESSION['origlink'].'&routerlink='.$_SESSION['routerlink'].'&siteid='.$_SESSION['siteid'], $permissions);

Is jquery not availble in integration test for rails 3.2 app?

We use a fields_for and jquery to add a partial view on a form in rails 3.2 app. Here is the code:
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
render :partial => association.to_s, :locals => {:f => builder, :i_id => 0}
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{j fields}\")")
end
In applicaton.js:
function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).parent().before(content.replace(regexp, new_id));
}
Whenever the 'Add Field' link is clicked, the partial view is rendered and a few input fields are added to the current form. The code works in execution without any problem. However in integration test (capybara & launchy), the click_link('Add Field') did not do anything and failed bringing up the partial. Is jquery not enabled in integration test?
By default Capybara use :rake_test driver on all tests, which is fast but dosen't support JavaScript.
Since this test needs JavaScript, make sure you have turned JS driver on.
describe "some feature", js: true do
# test code
end
This will use default JS driver Selenium.

Rails 3, how to prevent ajax remote calls (jquery) with a link_to and :remote => true with JS

So I have a simple ajax call to a page:
= link_to 'click me', my_path, :onclick => "if ($('#go').val() == "ok") { alert('going'); } else { return false; }", :remote => true do
This works just fine, I see the alert only when my field with id "go" has ok in there... but the issue is that the remote action triggers every time no matter what.
If this was not a remote link it would work just fine, not going through with the link, but it does not seem to behave the same way with a :remote => true ?
How can I achieve the expected result ?
Thanks,
ALex
The issue here is that the Rails UJS driver will see the data-remote and then perform the action because of a function like this in rails.js so perhaps try setting the property om your link inside the JS and remove the :remote => true. That might work however I dont know if rails.js would bind to that correctly or not.
Also, consider placing this JS in the application.js once you're done debugging just so you dont have inline JS all over your controllers.