AngularJS + Jasmine: Comparer des objets
Je viens juste de commencer à écrire des tests pour mon application AngularJS et fais en de Jasmin.
Voici les extraits de code
ClientController:
'use strict';
adminConsoleApp.controller('ClientController',
function ClientController($scope, Client) {
//Get list of clients
$scope.clients = Client.query(function () {
//preselect first client in array
$scope.selected.client = $scope.clients[0];
});
//necessary for data-binding so that it is accessible in child scopes.
$scope.selected = {};
//Current page
$scope.currentPage = 'start.html';
//For Client nav bar
$scope.clientNavItems = [
{destination: 'features.html', title: 'Features'},
];
//Set current page
$scope.setCurrent = function (title, destination) {
if (destination !== '') {
$scope.currentPage = destination;
}
};
//Return path to current page
$scope.getCurrent = function () {
return 'partials/clients/' + $scope.currentPage;
};
//For nav bar highlighting of active page
$scope.isActive = function (destination) {
return $scope.currentPage === destination ? true : false;
};
//Reset current page on client change
$scope.clientChange = function () {
$scope.currentPage = 'start.html';
};
});
ClientControllerSpec:
'use strict';
var RESPONSE = [
{
"id": 10,
"name": "Client Plus",
"ref": "client-plus"
},
{
"id": 13,
"name": "Client Minus",
"ref": "client-minus"
},
{
"id": 23805,
"name": "Shaun QA",
"ref": "saqa"
}
];
describe('ClientController', function() {
var scope;
beforeEach(inject(function($controller, $httpBackend, $rootScope) {
scope = $rootScope;
$httpBackend.whenGET('http://localhost:3001/clients').respond(RESPONSE);
$controller('ClientController', {$scope: scope});
$httpBackend.flush();
}));
it('should preselect first client in array', function() {
//this fails.
expect(scope.selected.client).toEqual(RESPONSE[0]);
});
it('should set current page to start.html', function() {
expect(scope.currentPage).toEqual('start.html');
});
});
Le test échoue:
Chrome 25.0 (Mac) ClientController should preselect first client in array FAILED
Expected { id : 10, name : 'Client Plus', ref : 'client-plus' } to equal { id : 10, name : 'Client Plus', ref : 'client-plus' }.
Error: Expected { id : 10, name : 'Client Plus', ref : 'client-plus' } to equal { id : 10, name : 'Client Plus', ref : 'client-plus' }.
at null.<anonymous> (/Users/shaun/sandbox/zong-admin-console-app/test/unit/controllers/ClientControllerSpec.js:43:39)
Quelqu'un a une idée sur le pourquoi de ce qui se passe?
Aussi .. comme je suis nouveau à l'écriture d'AngularJS tests, les commentaires de savoir si je suis la mise en place de mon test de mal ou si elle peut être améliorée sera la bienvenue.
Mise à jour:
Y Compris ClientService:
'use strict';
AdminConsoleApp.services.factory('Client', function ($resource) {
//API is set up such that if clientId is passed in, will retrieve client by clientId, else retrieve all.
return $resource('http://localhost:port/clients/:clientId', {port: ':3001', clientId: '@clientId'}, {
});
});
Aussi, j'ai reçu de contourner le problème en comparant les id à la place:
it('should preselect first client in array', function () {
expect(scope.selected.client.id).toEqual(RESPONSE[0].id);
});
- Il est possible de jasmin est la vérification de la non-propres propriétés. Ils ne s'affichent pas dans le JSON.stringify-ed version, mais ils vont être pris en compte pour la comparaison
- Probablement non, mais juste pour être sûr, assurez-vous de vous échapper de votre numéro de port; étranger, les choses ont passé...
$httpBackend.whenGET('http://localhost\\:3001/clients').respond(RESPONSE);
j'ai eu un SOUFFLE pour une heure à essayer de déchiffrer une erreur qui a fini par être l'un sans échappement numéro de port, FWIW. - merci pour l'astuce, mais quand j'ai essayé de s'échapper le numéro de port, comme la façon dont vous l'avez fait, j'obtiens une exception: Erreur: Inattendu de la demande: OBTENIR localhost:3001/clients Pas plus de demande prévu
- pouvez-vous nous en dire un peu plus? j'ai eu de contourner le problème en comparant le champ 'id' au lieu de la totalité de l'objet, mais je suis toujours curieux de savoir pourquoi l'objet de la comparaison échoué. une possibilité est que la portée.sélectionné.client contient en fait un $objet de la ressource..
- C'est ce qui explique un peu plus je pense : stackoverflow.com/questions/8779249/...
Vous devez vous connecter pour publier un commentaire.
toEqual
fait une profonde comparaison d'égalité. Ce qui signifie que lorsque toutes les propriétés des objets de valeurs sont égales, les objets sont considérés comme étant égaux.Comme vous l'avez dit, vous êtes en utilisant des ressources qui ajoute un couple de propriétés à des objets dans le tableau.
Donc ce
{id:12}
devient ce{id:12, $then: function, $resolved: true}
qui ne sont pas égaux. Contrôle d'identité doit être fine si vous êtes tout simplement de le tester si vous définissez les valeurs correctement.Réponse courte:
L'existant répond à toutes les recommander stringifying vos objets, ou la création d'une correspondance personnalisée/fonction de comparaison. Mais, il y a un moyen plus simple: utiliser
angular.equals()
dans votre Jasminexpect
appel, au lieu d'utiliser le Jasmin est intégré danstoEqual
matcher.angular.equals()
ignore les propriétés supplémentaires ajoutés à vos objets par Angulaire, alors quetoEqual
va échouer la comparaison pour, disons,$promise
être sur l'un des objets.Une longue explication:
J'ai couru à travers ce même problème dans mon application AngularJS. Nous allons définir le scénario:
Dans mon test, j'ai créé un objet local et d'un local de tableau, et espérer que les réponses à deux requêtes GET. Par la suite, j'ai comparé le résultat de l'OBTENIR avec l'objet original et tableau. J'ai testé à l'aide de quatre méthodes différentes et un seul a donné des résultats corrects.
Voici une partie de foobar-controller-spec.js:
Pour référence, voici la sortie de
console.log
à l'aide deJSON.stringify()
et.toString()
:Remarquez comment le stringified objet a des propriétés supplémentaires, et comment
toString
les rendements des données non valides qui va donner un faux positif.En regardant ci-dessus, voici un résumé des différentes méthodes:
expect(scope.foobar).toEqual(foobar)
: Ce ne sont pas les moyens. Lorsque l'on compare les objets, toString révèle que Angulaire a ajouté des propriétés supplémentaires. Lorsque l'on compare les tableaux, le contenu semblent identiques, mais cette méthode prétend toujours qu'ils sont différents.expect(scope.foo.toString()).toEqual(myFooObject.toString())
: Cela passe dans les deux sens. Cependant, c'est un faux positif, puisque les objets ne sont pas entièrement traduites. La seule affirmation de ce fait est que les deux arguments ont le même nombre d'objets.expect(JSON.stringify(scope.foo)).toEqual(JSON.stringify(myFooObject))
: Cette méthode donne la bonne réponse lors de la comparaison des tableaux, mais l'objet de comparaison a une semblable faute à la crue de comparaison.expect(angular.equals(scope.foo, myFooObject)).toBe(true)
: C'est la bonne façon de faire de l'assertion. En laissant Angulaire de faire la comparaison, il sait ignorer toutes les propriétés qui ont été ajoutés dans le backend, et donne le bon résultat.Si important pour tout le monde, je suis en utilisant AngularJS 1.2.14 et Karma 0.10.10, et l'essai sur la PhantomJS 1.9.7.
angular.equals
était ma solution.JSON.stringify
, être conscient qu'il ne garantit pas que les clés de l'objet sera dans le même ordre.{foo: 1, bar:2}
permettra d'évaluer de ne pas égal à{bar: 2, foo: 1}
JSON.stringify
ne peut pas faire confiance à comparer des objets.Longue histoire courte: ajouter
angular.equals
comme un jasmin matcher.Oui, alors vous pouvez l'utiliser comme suit:
angular.equals
. Mon seul souci serait qu'il pourrait obtenir à confusion se souvenir de ce qui "est égal à" matcher vous avez besoin dans une situation donnée.toAngularEqual
exprime mieux pourquoi ces deux sont différents. Ce texte n'est cette impression si elles ne sont pas égales? Pas un grand fan de juste avoir le message d'erreur "Devrait faux, est égal à true'.J'ai juste eu un problème similaire et mis en œuvre une correspondance personnalisée comme suit, basée sur de nombreuses approches:
puis utilisé de cette façon:
Bien sûr, c'est un très simple de correspondance et ne prend pas en charge de nombreux cas, mais je n'ai pas besoin de rien de plus complexe que cela. Vous pouvez envelopper le rapprochement dans un fichier de config.
Vérifier cette réponse pour une mise en œuvre similaire.
J'ai eu le même problème donc j'ai juste appelé
JSON.stringify()
sur les objets à comparer.JSON.stringify
sur un objet dans le Jasmin a peut être égal à un objet vide de sorte que le test lui-même va passer mais en fait il ne vérifiant pas les objets de l'égalité. Voir les réponses ci-dessus.JSON.stringify(someObject, null, 4)
pour embellir vos objets avant de les comparer. Si l'une de vos affirmations échoue, alors la sortie sera bien plus lisible.Un peu verbeux, mais produit utile de message lors de l'attente échoue:
Explication:
angular.toJson
bande de la ressource de tous angulaire des propriétés spécifiques comme$promise
JSON.parse
va convertir la chaîne JSON retour à la normale de l'Objet (ou un Tableau), qui peut maintenant être comparé à un autre Objet (ou un Tableau).