I have a single acceptance test in Ember.js 1.10, Ember CLI 0.1.12 which fails on PhantomJS but runs fine in both Chrome and Firefox. I've tried to debug this for 2 days but I'm running out of ideas. Name of the test is user can view logged-only pages when he is logged. Basically when you are not logged and you try to access classic route, for example /about you are redirected to start.login in beforeModel hook of classic route:
beforeModel: ->
if not #controllerFor('application').get 'logged'
#transitionTo 'start.login'
When you are on start.login and you will give correct name and username, logIn action in StartLoginController will be called:
logIn: ->
if not #get('logged')
#get('controllers.application').send 'logIn', #get('username'), #get('password'), #get('rememberMe')
Which calls following action in ApplicationController:
actions:
logIn: (username, password, remember) ->
if not #get 'logged'
$.ajax
url: #get('apiURL') + '/auth/login'
type: 'POST'
data:
name: username
password: password
remember: remember
xhrFields:
withCredentials: true #ensure CORS
.then (response) =>
if response.success
expires = if remember then new Date(response.cookieExpiration) else null
$.cookie 'auth_user_id', response.user.id,
expires: expires
path: '/'
$.cookie 'auth_expiration', response.cookieExpiration,
expires: expires
path: '/'
#setProperties
logged: true
'controllers.auth.userId': response.user.id
#transitionToRoute 'classic.index'
, =>
#send 'openModal', 'modal/wrong-credentials'
false
And this works fine even in PhantomJS. Other tests pass. Actions are called correctly, properties are set correctly, cookies are set correctly. Even beforeModel hook correctly calls(or not) transitionTo method. I've thought that issue with PhantomJS is with some async order of calling things but I've tried wrapping code in Ember.run and andThen in many places. No luck at all.
testem.json:
{
"framework": "qunit",
"test_page": "tests/index.html?hidepassed",
"launch_in_ci": [
"PhantomJS"
],
"launch_in_dev": [
"PhantomJS",
"Chrome",
"Firefox"
]
}
Acceptance test login-test.coffee(failing test is the last one):
`import Ember from 'ember'`
`import startApp from '../helpers/start-app'`
application = null
run = Ember.run
login = ->
visit '/'
fillIn '[placeholder=Login]', 'test'
fillIn '[placeholder=Hasło]', 'test'
click '.button-login'
clearCookies = ->
cookies = $.cookie()
for cookie of cookies
$.removeCookie cookie,
path: '/'
cookies = document.cookie.split ';'
for i in [0...cookies.length] by 1
equals = cookies[i].indexOf '='
name = if equals > -1 then cookies[i].substr(0, equals) else cookies[i]
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"
module 'Acceptance: Login',
setup: ->
application = startApp()
clearCookies()
time = new Date()
$.mockjaxSettings.logging = false
$.mockjax
type: 'POST'
url: 'api/v1/auth/login'
dataType: 'json'
responseText:
success: true
user:
id: 1
cookieExpiration: time.setDate time.getDate() + 14
$.mockjax
type: 'GET'
url: '/api/v1/users/1'
dataType: 'json'
responseText:
user:
id: 1
$.mockjax
type: 'GET'
url: '/api/v1/statuses' # ?limitOld=10&friends=true&comments[limit]=5
data:
comments:
limit: 5
friends: true
limitOld: 10
responseText:
statuses: {}
$.mockjax
type: 'GET'
url: '/api/v1/getRandomQuote'
$.mockjax
type: 'GET'
url: '/api/v1/statuses/?friends=true&count=true'
responseText:
count: 0
$.mockjax
type: 'GET'
url: '/api/v1/meals'
$.mockjax
type: 'GET'
url: '/api/v1/notifications'
$.mockjax
type: 'GET'
url: '/api/v1/notifications'
data:
read: false
responseText: {}
return
teardown: ->
$.mockjax.clear()
clearCookies()
run application, 'destroy'
test 'user lands on default page when he is not logged', ->
expect 1
visit '/'
andThen ->
equal currentPath(), 'start.login'
test 'login page is displayed when you are trying to access logged-only page', ->
expect 1
visit '/kitchen'
andThen ->
equal currentPath(), 'start.login'
test 'user can login', ->
expect 2
appController = application.__container__.lookup 'controller:application'
equal appController.get('logged'), false, 'user is not logged before login'
login()
andThen ->
ok appController.get 'logged', 'user is logged when response is success'
test 'user can view logged-only pages when he is logged', ->
expect 2
console.log '-- LOGGED-ONLY TEST START --'
visit '/about'
andThen ->
equal currentPath(), 'start.login'
login()
visit '/about'
andThen ->
equal currentPath(), 'classic.about'
And finally output from tests:
TEST'EM 'SCRIPTS!
Open the URL below in a browser to connect.
http://localhost:7357/
━━━━━━━━━━━━━━┓
PhantomJS 1.9┃ Firefox 37.0
198/199 ✘ ┃ 199/199 ✔
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Acceptance: Login: user can view logged-only pages when he is logged
✘ failed
expected classic.about
actual start.login
-- LOGGED-ONLY TEST START --
I don't think classic.about is source of error, because replacing it with other child routes of classic resource result in same PhantomJS failing test.
Okay so it seems that problem lies in model for ClassicRoute(commenting that makes test pass):
model: ->
new Promise (resolve, reject) =>
#store.find 'user', #controllerFor('auth').get('userId')
.then (user) =>
#controllerFor('auth').set 'user', user
resolve
profile: user.get 'profile'
I've split logic in two hooks instead of one and it works now:
beforeModel: ->
if not #controllerFor('application').get 'logged'
#transitionTo 'start.login'
else
#store
.find 'user', #controllerFor('auth').get('userId')
.then (user) =>
#controllerFor('auth').set 'user', user
#set 'profileId', user.get('profile.id')
model: ->
#store.find 'profile', #get('profileId')
Related
I have a Django as backend and updating the user from postman is working fine. But when I update it via React Frontend, it replies with a success message just as in Postman, but the data was not updated.
This is the update function to update:
const updateData = (e) => {
e.preventDefault();
const csrftoken = getCookie("csrf");
const cookies = new Cookies();
const url = "http://localhost:8000/usercontrol/update";
setIsLoading(true);
fetch(url, {
method: "PUT",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Token " + cookies.get("token"),
"X-CSRFToken": csrftoken,
},
body: JSON.stringify({
email: userinfo.email,
username: userinfo.username,
first_name: userinfo.first_name,
last_name: userinfo.last_name,
}),
}).then((response) => console.log("THE RESPONSE: ", response.json()));
setIsLoading(false);
};
This is what it prints out in the console
Since I am partially following CodingWithMitch for Django user creation with rest framework is similar to his.
Furthermore, since there is no error outputting and is working fine in Postman, I have no idea what is wrong with it.
I'm trying to figure out how to send JSON via post from jQuery to a Rails app and save the JSON data as a session variable. Here is what I have so far:
jQuery Code
info = '{"data": {"color": "green"}}'
$.ajax({
type: "POST",
url: '/cart/save-design',
data: info,
cache: false,
success: function(data){
alert("OK");
},
error: function(){
}
});
Rails Controller Code
def save_design
data = json_params
session[:check] = data
head :no_content
end
private
def json_params
params.require(:data).permit(:color)
end
Server Error Log
Started POST "/cart/save-design" for 127.0.0.1 at 2015-09-03 12:52:37 -0700
Processing by CartsController#save_design as */*
Parameters: {"{\"data\": {\"color\": \"green\"}}"=>nil, "locale"=>"en"}
MOPED: 127.0.0.1:27017 QUERY database=abc_development collection=sessions selector={"$query"=>{"_id"=>"Lroqq29V1QVt7ebIM5ENwFeN0FM"}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil runtime: 0.6210ms
Completed 400 Bad Request in 7ms
ActionController::ParameterMissing (param is missing or the value is empty: data):
app/controllers/carts_controller.rb:47:in `json_params'
app/controllers/carts_controller.rb:30:in `save_design'
It would seem the problem is with my strong params but I can't figure out why.
Add dataType: 'json' to your AJAX call:
$.ajax({
type: "POST",
url: '/cart/save-design',
data: info,
dataType: 'json',
cache: false,
success: function(data){
alert("OK");
},
error: function(){
}
});
And make sure info is a valid JavaScript object, not a plain String.
I want to store the user id in the session. I have this authenticate method in a custom authenticator :
authenticate: (credentials) ->
_this = this
new (Ember.RSVP.Promise) (resolve, reject) ->
Ember.$.ajax(
url: 'http://localhost:3000/api/v1/sessions'
type: 'POST'
data: session:
email: credentials.identification
password: credentials.password
).then ((response) ->
_this.set('user_id', response.user_id)
Ember.run ->
resolve token: response.token
), (xhr, status, error) ->
response = JSON.parse(xhr.responseText)
Ember.run ->
reject response.error
It's coffee script but it works like javascript. As you can this, I set 'user_id' in the session.
In app/initializers/custom-session, I have this :
import Ember from "ember";
import Session from "simple-auth/session";
export default {
name: "current-user",
before: "simple-auth",
initialize: function(container) {
Session.reopen({
setCurrentUser: function() {
return this.get('user_id')
}.observes('secure.access_token')
});
}
};
user_id always returns undefined. I found many solutions on the Internet but nothing works.
Is there a simple solution to do that?
You are setting the user_id on the authenticator (_this.set('user_id', response.user_id)) instead of the session. The user_id should be passed to the resolve method in your authenticator. That way your user id is accessible by secure.user_id in your session.
I want to get the users Geolocation. Once I get the coordinates, I want to load Records based on that Geolocation. If there is more than 1 result, show an index page,
LHW.Store = DS.Store.extend
revision: 11
adapter: DS.RESTAdapter
DS.RESTAdapter.reopen
namespace: 'api'
LHW.Company = DS.Model.extend
name: DS.attr 'string'
address: DS.attr 'string'
city: DS.attr 'string'
LHW.IndexRoute = Ember.Route.extend
setupController: (controller, route) ->
# get Geolocation
_route = #
navigator.geolocation.getCurrentPosition ((location) ->
#success
_route.geoLocation(location)
), (error) ->
#error
switch(error.code)
when error.PERMISSION_DENIED then console.log "User denied the request for Geolocation."
when error.POSITION_UNAVAILABLE then console.log "Location information is unavailable."
when error.TIMEOUT then console.log "The request to get user location timed out."
when error.UNKNOWN_ERROR then console.log "An unknown error occurred."
geoLocation: (location) ->
_route = #
#get('store').findQuery('company',{longitude: location.coords.longitude, latitude: location.coords.latitude}).then ((data) =>
_route.controllerFor('companies').set('content', data)
if data.get('length') > 1
_route.transitionTo('companies');
), (error) ->
console.log "error"
LHW.CompaniesRoute = Ember.Route.extend()
LHW.IndexController = Ember.ArrayController.extend
beforeModel: ->
console.log 'before'
So this is what I got now. But this has a few problems
If you go to /companies instead of / It skips the geolocation
check. But if I move the geolocation to the companies route, then
what is the page the users sees while geolocation is getting
fetched?
Creating a switch and checking the length in a route,
feels a bit dirty, imo the Companyroute should respond to that
So this is mostly a flow issue I can't wrap my head around and the async geolocation isn't making things easier...
I've made a login system with Ember.js and Rails . So I tried to make redirection for non-authenticated users. I don't know where I must do the redirection (the application controller or in the application route ? ).
Here's my auth system :
window.AuthApp = Ember.Object.extend(Ember.Evented).create
authToken: null
currentUserId: null
signIn: (data) ->
if data == null
data = {}
if data['remember'] == true
cookie = true
$.ajax 'api/login',
type: 'POST'
dataType: 'JSON',
contentType: 'application/json; charset=utf-8'
data: JSON.stringify(data)
error: ->
alert('Error signIn')
success: (data) ->
console.log(data)
AuthApp.set 'authToken', data['auth_token']
if cookie == true
$.cookie 'remember_token', data['auth_token'],
expires: 7
AuthApp.Module.RememberMe = Ember.Object.create
recall: ->
if ($.cookie('remember_token'))
data = {}
data['auth_token'] = $.cookie('remember_token')
AuthApp.signIn(data)
return true
As you can see, I've just to call AuthApp.Module.Remember.recall() for check if an user is connected or not.
Thanks for your help
You should take a look at the router-facelift. One of the design goals was to make authentication-based apps less difficult to implement.
https://gist.github.com/machty/5723945