angularjs - 如何用 Angular 和 Jasmine 模拟 socket.io

标签 angularjs socket.io jasmine angular-mock

我无法弄清楚如何使用 Jasmine 和 Karma 在 Angular 应用程序中正确模拟 Socket.io。

以下是在 karma.conf.js 中找到的文件:

'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/angular-socket-io/socket.js',
'bower_components/socket.io-client/socket.io.js',
'bower_components/angular-socket-io/mock/socket-io.js',
'public/javascripts/*.js',
'ng_tests/**/*.js',
'ng_tests/stateMock.js'

这是我的 Controller 的样子:

var lunchrControllers = angular.module('lunchrControllers', []);

lunchrControllers.controller('UserMatchingController', ['$state', 'socket',
    function ($state, socket) {
        socket.emit('match');

        socket.on('matched', function (data) {
            $state.go('users.matched', {name: data.name})
        });
    }]);

这是我的套接字工厂:

var lunchrFactories = angular.module('lunchrFactories', []);

lunchrFactories.factory('socket', function (socketFactory) {
    return socketFactory();
});

这是主要的 Angular 模块:

var lunchrApp = angular.module('lunchr', ['ui.router', 'btford.socket-io', 'lunchrControllers', 'lunchrFactories' ]);

lunchrApp.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
    function ($stateProvider, $urlRouterProvider, $locationProvider) {
        $urlRouterProvider.otherwise('/');

        $stateProvider.
            state('mainPage', {
                url: '/',
                templateUrl: '/partials/main.jade',
                controller: 'MainPageController'
            })
            .state('users', {
                url: '/users',
                templateUrl: '/partials/users.jade',
                controller: 'UserController'
            })
            .state('users.matching', {
                url: '/matching',
                templateUrl: '/partials/users.matching.jade',
                controller: 'UserMatchingController'
            })
            .state('users.matched', {
                url: '/matched',
                templateUrl: '/partials/users.matched.jade',
                params:{name:null},
                controller: 'UserMatchedController'
            })
            .state('register', {
                url:'/register',
                templateUrl: 'partials/register.jade',
                controller: 'RegisterController'
            });
        $locationProvider.html5Mode(true);
    }]);

这是我无法理解的测试:

'use strict';

describe('UserMatchingController', function () {
    beforeEach(module('lunchr'));
    beforeEach(module('stateMock'));


    var $controller, $rootScope, $state, socket;

    beforeEach(inject(function ($injector) {
        // Get hold of a scope (i.e. the root scope)
        $rootScope = $injector.get('$rootScope');

        $state = $injector.get('$state');

        // The $controller service is used to create instances of controllers
        $controller = $injector.get('$controller');

        socket = $injector('socket');
    }));

    afterEach(function () {
        $state.ensureAllTransitionsHappened();
    });

    function createController() {
        return $controller('UserMatchingController', {'$scope': $rootScope});
    }

    describe('on initiazation', function(){
        it('socket should emit a match', function() {
            createController();

            // would like to be able to expect a socket.emit call
        });
        it('should transition to users.matched upon receiving matched', function(){
            createController();
            $state.expectTransitionTo('user.matched');
            socket.receive('matched', {name: 'Ben'}); //This errors out with: cannot read property 'receive' of undefined
        })
    })
});

我怀疑 socket 没有被正确注入(inject),我不确定如何修复它。同样,我也希望能够调用 socket.emit 但不知道如何调用。

如有任何帮助,我们将不胜感激。

编辑:我想使用 this socket mock如果可能的话,但我无法弄清楚它到底是如何工作的。

最佳答案

我会使用 Sinon.js创建模拟套接字对象。

例如,在你的beforeEach中,将socket初始化为一个空对象:

socket = {};

createController() 必须将 mock 传递给 Controller ​​:

$controller('UserMatchingController', {'$scope': $rootScope, 'socket': socket});

然后在你的测试中做这样的事情:

socket.emit = sinon.spy(); //Create a spy so we can check if it was called
createController();

expect(socket.emit).toHaveBeenCalledWith('match');

您将需要软件包 sinonjasmine-sinon .此外,如果您使用的是 Karma,则需要 karma-sinon .您可以在相应页面上找到有关设置的更多指南。

编辑:在您的情况下,您的模拟每次都需要具有 onemit 功能,因为 Controller 需要它们。在这种情况下,将其放入 beforeEach 函数中可能会更好:

socket = {
  emit : sinon.spy(),
  on : sinon.spy()
};

关于angularjs - 如何用 Angular 和 Jasmine 模拟 socket.io,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28846048/

相关文章:

javascript - 当在我的 html 脚本标记上使用 async ='true' 来加载 socket.io.js 时,它会导致 io 对象出现未定义的错误,有什么建议吗?

javascript - Socket.io 使用 mongoDB 文档发出 [object Object]

unit-testing - angular2 测试,如何模拟子组件

linux - 找不到变量 : loadFixtures

javascript - 具有函数绑定(bind)的 Angular 日期选择器指令

javascript - Angularjs ng-click() 不是从 ng-repeat 指令触发

javascript - AngularJS Controller 功能未触发

javascript - AngularJs - 无法使用 ng-click 传递 ng-repeat 生成的对象

javascript - 获取用户id socket.io, passport, koa

javascript - Protractor - 在端到端测试中检查字符串不为空的最佳方法