I have a module App which will check if the user has sign in.
App.run ['$rootScope', 'UserService', ($rootScope, UserService) ->
UserService.current_user()
]
The UserService.current_user() will trigger a $http request.
So how can i write the $httpBackend to mockup the request? I have tried some method:
describe 'App', ->
$httpBackend = null
beforeEach(module('App')) # one
beforeEach inject ($injector) -> # two
$httpBackend = $injector.get('$httpBackend')
$httpBackend
.when('GET', '/api/1/users/current_user')
.respond(403, {"error":"not signin"})
it "should get current_user request", () ->
$httpBackend.expectGET('/api/1/users/current_user').respond(403, {'error': 'not signin'})
This will show the error:
Error: Unexpected request: GET /api/1/users/current_user No more request expected
If I change the sequence of # one and # two. It will show error
Error: Injector already created, can not register a module!
This makes me fall in depression. I need some help.
I made it working with this :
describe 'App', ->
beforeEach angular.mock.module('App')
it "should get current_user request", inject ($httpBackend) ->
$httpBackend.expectGET('/api/1/users/current_user').respond(403, {'error': 'not signin'})
$httpBackend.flush()
And it works also if you put the backend expectation in a before each :
describe 'App', ->
beforeEach angular.mock.module('App')
beforeEach inject ($httpBackend) ->
$httpBackend.expectGET('/api/1/users/current_user').respond(403, {'error': 'not signin'})
$httpBackend.flush()
it 'should test someting else', ->
See it in action in this Plunker.
Related
I have this redux-observable epic which does a POST ajax request using RxJS.ajax.post and I don't think it is hitting my Elixir router properly as nothing is happening on my elixir backend. I am doing get requests to get categories correctly and in the same manner so I am hitting other paths in my Elixir router correctly. I am expecting the issue to be with my backend Elixir code not my frontend. I might need to change my path in router.ex.
When I press a button on the frontend, this object is what gets sent to the elixir backend (it dispatches this action with a product as the payload and hits the redux-observable epic below):
onPress = {() => {
props.uploadProduct({
name: props.name,
brand: props.brand,
description: props.description,
image: props.image
})
The epic:
import { ajax } from 'rxjs/observable/dom/ajax'
import { Observable } from 'rxjs'
export const uploadProductEpic = action$ =>
action$.ofType(UPLOAD_PRODUCT)
.mergeMap(action => {
ajax.post('http://localhost:4000/products/', action.payload)
})
.map(response => uploadProductFulfilled(response))
.catch(error => Observable.of(
uploadProductRejected(error))
)
the elixir router:
defmodule Api.Router do
use Plug.Router
if Mix.env == :dev do
use Plug.Debugger
end
plug :match
plug :dispatch
get "/categories/" do
Api.Repo.getCategories(conn)
end
post "/products/:product" do
IO.puts inspect conn
Api.Repo.insertProduct(conn, product)
end
end
IO.puts inspect conn doesn't log anything. So My Elixir router path post "/products/:product" do is not being hit by my POST request. What am I doing wrong?
This is the elixir function in repo.ex that I HOPE will insert the product into my database:
def insertProduct(conn, product) do
product = %Api.Product{name: product.name, brand: product.brand, description: product.description, image: product.image, rating: 0, numberOfVotes: 0}
changeset = Api.Product.changeset(product)
errors = changeset.errors
valid = changeset.valid?
case insert(changeset) do
{:ok, product} ->
conn
|> put_resp_content_type("application/json")
|> send_resp(200, Poison.encode!(%{
successs: "success"
}))
{:error, changeset} ->
conn
|> put_resp_content_type("application/json")
|> send_resp(500, Poison.encode!(%{
failure: "Errors"
}))
end
end
I am a frontend developer just trying to get into Elixir so any guidance and patience is appreciated. Thanks.
Your data is sent in the body of the request, not in the URL, so the route should be:
post "/products"
You'll also need to plug in a JSON parser after plug :match and before plug :dispatch, as described in the Parameter Parsing section in the documentation of Plug.Router:
plug :match
plug Plug.Parsers, parsers: [:json],
pass: ["application/json"],
json_decoder: Poison
plug :dispatch
The JSON data will now be present in conn.body_params, which you can send to your function:
post "/products" do
Api.Repo.insertProduct(conn, conn.body_params)
end
And finally, the keys in the JSON would be strings, so you need to use the bracket syntax to access them instead of dots:
product = %Api.Product{name: product["name"], brand: product["brand"], description: product["description"], image: product["image"], rating: 0, numberOfVotes: 0}
I'm not sure how you've defined Api.Product.changeset, but the default Phoenix convention defines a 2 arity function which calls cast and extracts the data from a map itself. If you're doing the same, you can do this instead:
changeset = Api.Product.changeset(%Api.Product{}, product)
I'm writing meteor tests that require authentication, and having a series of problems.
This is my code:
MochaWeb?.testOnly ->
describe "Login", ->
describe "security", ->
it 'should take you to /login/ if you are not logged in', ->
Meteor.flush()
chai.assert.equal Router.current().url, '/login/'
it 'should allow logins and then take us to /', ->
Meteor.flush()
Accounts.createUser username: 'test', password: 'test'
Meteor.loginWithPassword 'test', 'test', (err) ->
console.log err
chai.expect(err).to.be undefined
chai.assert.equal Router.current().url, '/'
My tests pass, even though I get console messages such as Exception in delivering result of invoking 'login': TypeError: object is not a function
My console.log call gives me
{error: 403, reason: "User not found", details: undefined, message: "User not found [403]", errorType: "Meteor.Error"…}
on the console, and nothing on the velocity log window
My user doesn't authenticate as I'd expect. One cause could be that my app doesn't have the accounts-password package, because I don't want it (I just want google apps users to be able to login). However I want an easy way to handle authentication in meteor tests, as most of my tests involve authenticated users.
I'm not sure whether the assert equal would work or I'd have to set some sort of timeout to wait for the redirection. In this case it wouldn't be a problem, but do I have to nest every test method I have inside loginWithPassword? I'd find this a bit uncomfortable.
Any help and suggestions much appreciated!
Best,
Are you sure you have user already created? I think you should create it in your fixture.js.
MochaWeb.testOnly(function() {
describe("Client", function() {
describe("firstTest", function() {
// Meteor.users.remove({});
before(function(done) {
Accounts.createUser(currentUser, function(err, success) {
Meteor.loginWithPassword(currentUser, function(err) {
console.log("This works");
// done();
});
});
});
});
});
});
Here is the source file, in which I have implemented the same
https://github.com/trinisofttechnologies/mocha-test/blob/master/tests/mocha/client/client.coffee
and this is the repo where the code resides
https://github.com/trinisofttechnologies/mocha-test
When trying to define a Parse Cloud Code server side function to handle login I get 400 Bad Request when I try to call it. When I look at the Parse logs it records the error "Failed with: ReferenceError: user is not defined". But the user is definitely defined!
Below is the definition of the cloud code for LogIn:
Parse.Cloud.define("LogIn", function(request, response)
{
user.logIn(request.params.username, request.params.password,
{
success: function(user)
{
response.success(
{
"success": "Log in successful."
});
},
error: function(user, error)
{
// We must respond with a success in order to access the
// result of the request inside Unity.
response.success(
{
"error": "Log in failed.",
"code": error.code,
"message": error.message
});
}
});
});
From Unity I make this call to the LogIn coud code function:
ParseCloud.CallFunctionAsync<Dictionary<string, object>> ("LogIn", userInfo).ContinueWith (t =>
{
etc.....
}
I get the following error logged in the server side Parse logs when I call the above from Unity using user sashas123 and also student123:
E2014-09-26T17:06:18.001Z] v8: Ran cloud function LogIn with: Input:
{"username":"sashas123","password":"test"} Failed with:
ReferenceError: user is not defined
at main.js:43:5
E2014-09-26T17:38:50.474Z] v10: Ran cloud function LogIn with:
Input: {"username":"student123","password":"test"} Failed with:
ReferenceError: user is not defined
at main.js:43:5
The following snapshot from the Data Browser shows that the above users are definitely defined:
![Parse User class][1]
Is there any issue with calling user.LogIn on the server side through Cloud Code or is this a Unity issue?
It looks like user.logIn should be request.user.logIn :)
I find it's best to handle the case where the function may be called without a logged in user too:
if (request.user.logIn != null)
{
...
}
else
{
response.error("This function must be called with a logged in user!");
}
Hope this help!
I am having some issues with testing my signin/signout and related features of my app. The app works, but the test fail.
For testing, I use a QUnit with testem (I also tried teaspoon)
test "after signin, should redirect user back to previous page", ->
visit '/library'
fillIn '.signin-email', 'example#example.com'
fillIn '.signin-password', 'examplepass'
click '.signin-btn'
andThen ->
equal(testing().path(), 'library', "Should redirect back to library (was #{testing().path()})")
After running the test, I get a failure:
(screenshot here )
Authentication: visiting restricted page as non authenticated user: after signin, should redirect user back to previous page (2, 0, 2)Rerun544 ms
{user_id: 2, auth_token: wVveiyDLuXBXu69pQ2XQwg}
Source:
at Test.QUnitAdapter.Test.Adapter.extend.exception (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:50149:5)
at superWrapper [as exception] (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:13374:16)
at Object.onerror (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:50009:22)
at onerror (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20453:16)
at EventTarget.trigger (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20286:22)
at null.<anonymous> (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20439:14)
at EventTarget.trigger (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20286:22)
at http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20588:17
Should redirect back to library (was signin)
Expected:
"library"
Result:
"signin"
Diff:
"library" "signin"
Source:
at http://localhost:7357/public/assets/spec/javascripts/integration/authentication_pages_spec.js.js:22:14
at andThen (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:50258:20)
at http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:49817:21
at isolate (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:49989:14)
at http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:49972:12
at invokeCallback (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20463:19)
at null.<anonymous> (http://localhost:7357/public/assets/application-aad0a1b2c887cc25124c361787446e83.js:20513:11)
Also, auth.coffee:
App.Auth = Em.Auth.extend
request: 'jquery'
response: 'json'
strategy: 'token'
session: 'cookie'
modules: [
'emberData',
'authRedirectable',
'actionRedirectable'
]
signInEndPoint: '/signin'
signOutEndPoint: '/signout'
tokenKey: 'auth_token'
tokenIdKey: 'user_id'
tokenLocation: 'param'
emberData:
userModel: 'user' # create user model on login
authRedirectable:
route: 'signin'
actionRedirectable:
signInRoute: 'library'
# signInSmart: true
# signInBlacklist: ['signin']
signOutRoute: 'index'
I am unable to find the source of the error, so maybe it is something to do with ember-auth. Any ideas would be very appreciated.
Update 1 [Jan 4th]:
I've written an additional test, which passes only halfway. The test is simpler than the previous in that it does not check a redirect, but only checks that the user name appears in the UI after signin.
test "after signin, TEST", ->
visit '/library'
fillIn '.signin-email', 'user#example.com'
fillIn '.signin-password', 'foobargaz'
click '.signin-btn'
andThen ->
ok exists('.menu-signout'), "signout button exists"
The assertions passes, but I get an additional error reporting the returned JSON as seen in this screenshot. The screenshot basically shows:
[Fail] {user_id: 2, auth_token: wVveiyDLuXBXu69pQ2XQwg}
[Pass] signout button exists
Additionally, I've also run the tests by mocking the ajax requests with mockjax, but with the same failure.
Third, I should note that I had to patch "ember-auth-request-jquery.js" to make it work with ember testing as suggested here
I'm pretty sure you're failing to wait on the first visit to happen, so here's how I read it (I'm no CS person)
You're telling Ember to go to library
Before being sure it's finished navigating you're trying to fill in 2 fields and click a button (all of which probably doesn't exist)
then you check to see if it's library, but while waiting after you thought you clicked, really the page finishes rendering the login page from the visit
Here's what js2coffe says it'd kind of look like (my main point is the then after the visit).
test "after signin, should redirect user back to previous page", ->
visit("/library").then ->
fillIn ".signin-email", "example#example.com"
fillIn ".signin-password", "examplepass"
click(".signin-btn").then ->
equal testing().path(), "library", "Should redirect back to library (was " + (testing().path()) + ")"
Update 1/4: Documentation changed on me
Now we move to educated guess time. Looking through the Ember-auth code it might not be creating any timers/promises that Ember is aware of, in affect Ember thinks it's finished the signin process immediately. So the click promise is resolved immediately and you run your test immediately (andThen waits on the global testing promise to resolve). To test the theory you can do some terrible timeout and see if it does indeed redirect after some time
test "after signin, should redirect user back to previous page", ->
visit "/library"
fillIn ".signin-email", "example#example.com"
fillIn ".signin-password", "examplepass"
click ".signin-btn"
stop()
Ember.run.later this, (->
start()
equal testing().path(), "library", "Should redirect back to library (was " + (testing().path()) + ")"
), 5000
It turns out my coffeescript was not the best in the world.
The module function in QUnit should NOT compile to:
module('Authentication: visiting restricted page as non authenticated user', function() {
return setup(function() {
return Em.run(App, App.advanceReadiness);
});
});
but to:
module('Authentication: visiting restricted page as non authenticated user', {
setup: function() {
Ember.run(App, App.advanceReadiness);
},
// This is also new
teardown: function() {
App.reset();
}
});
Additionally, in my spec_helper.coffee file I had something like this:
QUnit.testStart(function() {
// FIXME: this below made it fail every time
// Ember.run(function() {
// return App.reset();
// });
Ember.testing = true;
});
QUnit.testDone(function() {
Ember.testing = false;
});
QUnit.done(function() {
return Ember.run(function() {
return App.reset();
});
});
which seems to have caused some issues, so I just deleted it and the tests now pass.
The frontend: AngularJS 1.1.5, which has ngResource returning a promise's $then function
The backend: Rails 3.2
The problem: Whenever I call the Card.update action from inside a function in an AngJS controller, I get no response from attempting to log both the success and error responses. The Card $resource behaves as expected works when calling the Card.update action from outside the function.
Rails Associations
Deck has_and_belongs_to_many :cards
Card has_and_belongs_to_many :decks
Rails routes
resources :cards do
get '/decks' => 'cards#decks', on: :member
end
Rails Card Controller 'update' action
def update
#card = Card.where( id: params[:id] ).first
unless params[:deck_id].nil?
#deck = Deck.where( id: params[:deck_id] ).first
#deck.cards << #card
end
render json: Card.update( params[:id], params[:card] )
end
Cards Resource Factory
app.factory "Card", ($resource) ->
$resource "/cards/:id",
id: "#id"
,
index:
method: "GET"
isArray: true
show:
method: "GET"
isArray: false
create:
method: "POST"
update:
method: "PUT"
destroy:
method: "DELETE"
decks:
method: "GET"
isArray: true
url: 'cards/:id/decks'
Cards update function (inside AngJS Controller): (Success/error messages aren't logged to the console).
$scope.updateCard = ( card_id, old_deck, new_deck ) ->
console.log 'CardCtrl updateCard function'
card_id = parseInt(card_id)
old_deck = parseInt(old_deck)
new_deck = parseInt(new_deck)
Card.update( id: card_id, deck_id: new_deck ).$then (success, error) ->
console.log 'Success'
console.log success
console.log 'Error'
console.log error
Introduction
I solved my own problem. I used this Github comment from Misko Hevery as reference.
Why my PUT request wasn't executing:
Apparently, in Angular 1.1.x, if you ever leave the angular execution context, you'll be outside of Angular's $scope.$apply function. In my case, I was working with JQuery UI's sortable function - whenever a Card was placed in a new Deck, I wanted to update the Deck's cards to reflect that update.
To the best of my understanding, because of this, I was outside the angular execution context. ngResource wouldn't execute the PUT statement and the $then function of the Angular's promise object will never be called.
The solution:
Simply wrapping the $scope.$apply function around the Card.updateaction allowed the action to execute, which subsequently allowed the $then function to execute. See the code example below for further clarification:
$scope.$apply ->
Card.update(
id: 1
deck_id: 2
front: "HELLO WORLD!"
).$then ((success) ->
console.log "Success"
console.log success
), (error) ->
console.log "Error"
console.log error