UNPKG

strong-remotingnext

Version:
260 lines (231 loc) 8.74 kB
// Copyright IBM Corp. 2014,2016. All Rights Reserved. // Node module: strong-remoting // This file is licensed under the Artistic License 2.0. // License text available at https://opensource.org/licenses/Artistic-2.0 var assert = require('assert'); var extend = require('util')._extend; var expect = require('chai').expect; var SharedClass = require('../lib/shared-class'); var factory = require('./helpers/shared-objects-factory.js'); var RemoteObjects = require('../'); describe('SharedClass', function() { var SomeClass; beforeEach(function() { SomeClass = factory.createSharedClass(); }); describe('constructor', function() { it('fills http.path from ctor.http', function() { SomeClass.http = { path: '/foo' }; var sc = new SharedClass('some', SomeClass); expect(sc.http.path).to.equal('/foo'); }); it('fills http.path using the name', function() { var sc = new SharedClass('some', SomeClass); expect(sc.http.path).to.equal('/some'); }); it('fills http.path using a normalized path', function() { var sc = new SharedClass('SomeClass', SomeClass, { normalizeHttpPath: true }); expect(sc.http.path).to.equal('/some-class'); }); it('does not require a sharedConstructor', function() { var myClass = {}; myClass.remoteNamespace = 'bar'; myClass.foo = function() {}; myClass.foo.shared = true; var sc = new SharedClass(undefined, myClass); var fns = sc.methods().map(getName); expect(fns).to.contain('foo'); expect(sc.http).to.eql({ path: '/bar' }); }); }); describe('sharedClass.methods()', function() { it('discovers remote methods', function() { var sc = new SharedClass('some', SomeClass); SomeClass.staticMethod = function() {}; SomeClass.staticMethod.shared = true; SomeClass.prototype.instanceMethod = function() {}; SomeClass.prototype.instanceMethod.shared = true; var fns = sc.methods().map(getFn); expect(fns).to.contain(SomeClass.staticMethod); expect(fns).to.contain(SomeClass.prototype.instanceMethod); }); it('returns all methods when includeDisabled is true', function() { var sc = new SharedClass('MySharedClass', MySharedClass); function MySharedClass() { // this page left intentionally blank } var inputNames = ['foo', 'bar']; sc.defineMethod(inputNames[0], {shared: false}); sc.defineMethod(inputNames[1], {shared: true}); var outputNames = sc.methods({includeDisabled: true}).map(function(m) { return m.name; }); expect(outputNames).to.eql(inputNames); }); it('only discovers a function once with aliases', function() { function MyClass() {} var sc = new SharedClass('some', MyClass); var fn = function() {}; fn.shared = true; MyClass.a = fn; MyClass.b = fn; MyClass.prototype.a = fn; MyClass.prototype.b = fn; var methods = sc.methods(); var fns = methods.map(getFn); expect(fns.length).to.equal(1); expect(methods[0].aliases.sort()).to.eql(['a', 'b']); }); it('discovers multiple functions correctly', function() { function MyClass() {} var sc = new SharedClass('some', MyClass); MyClass.a = createSharedFn(); MyClass.b = createSharedFn(); MyClass.prototype.a = createSharedFn(); MyClass.prototype.b = createSharedFn(); var fns = sc.methods().map(getFn); expect(fns.length).to.equal(4); expect(fns).to.contain(MyClass.a); expect(fns).to.contain(MyClass.b); expect(fns).to.contain(MyClass.prototype.a); expect(fns).to.contain(MyClass.prototype.b); function createSharedFn() { var fn = function() {}; fn.shared = true; return fn; } }); it('should skip properties that are model classes', function() { var sc = new SharedClass('some', SomeClass); function MockModel1() {} MockModel1.modelName = 'M1'; MockModel1.shared = true; SomeClass.staticMethod = MockModel1; function MockModel2() {} MockModel2.modelName = 'M2'; MockModel2.shared = true; SomeClass.prototype.instanceMethod = MockModel2; var fns = sc.methods().map(getFn); expect(fns).to.not.contain(SomeClass.staticMethod); expect(fns).to.not.contain(SomeClass.prototype.instanceMethod); }); }); describe('sharedClass.defineMethod(name, options)', function() { it('defines a remote method', function() { var sc = new SharedClass('SomeClass', SomeClass); SomeClass.prototype.myMethod = function() {}; var METHOD_NAME = 'myMethod'; sc.defineMethod(METHOD_NAME, { prototype: true }); var methods = sc.methods().map(getName); expect(methods).to.contain(METHOD_NAME); }); it('defines a remote method with accessType', function() { var sc = new SharedClass('SomeClass', SomeClass); SomeClass.prototype.myMethod = function() {}; var METHOD_NAME = 'myMethod'; sc.defineMethod(METHOD_NAME, { prototype: true, accessType: 'READ' }); var methods = sc.methods().map(getName); expect(methods).to.contain(METHOD_NAME); expect(sc.find(METHOD_NAME).accessType).to.eql('READ'); }); it('should allow a shared class to resolve dynamically defined functions', function(done) { var MyClass = function() {}; var METHOD_NAME = 'dynFn'; process.nextTick(function() { MyClass[METHOD_NAME] = function(str, cb) { cb(null, str); }; done(); }); var sharedClass = new SharedClass('MyClass', MyClass); sharedClass.defineMethod(METHOD_NAME, {}); var methods = sharedClass.methods().map(getName); expect(methods).to.contain(METHOD_NAME); } ); }); describe('sharedClass.resolve(resolver)', function() { it('should allow sharedMethods to be resolved dynamically', function() { function MyClass() {} MyClass.obj = { dyn: function(cb) { cb(); } }; var sharedClass = new SharedClass('MyClass', MyClass); sharedClass.resolve(function(define) { define('dyn', {}, MyClass.obj.dyn); }); var methods = sharedClass.methods().map(getName); expect(methods).to.contain('dyn'); }); }); describe('sharedClass.find()', function() { var sc; var sm; beforeEach(function() { sc = new SharedClass('SomeClass', SomeClass); SomeClass.prototype.myMethod = function() {}; var METHOD_NAME = 'myMethod'; sm = sc.defineMethod(METHOD_NAME, { prototype: true }); }); it('finds sharedMethod for the given function', function() { assert(sc.find(SomeClass.prototype.myMethod) === sm); }); it('find sharedMethod by name', function() { assert(sc.find('myMethod') === sm); }); }); describe('remotes.addClass(sharedClass)', function() { it('should make the class available', function() { var CLASS_NAME = 'SomeClass'; var remotes = RemoteObjects.create(); var sharedClass = new SharedClass(CLASS_NAME, SomeClass); remotes.addClass(sharedClass); var classes = remotes.classes().map(getName); expect(classes).to.contain(CLASS_NAME); }); }); describe('sharedClass.disableMethod(methodName, isStatic)', function() { var sc; var sm; var METHOD_NAME = 'testMethod'; var INST_METHOD_NAME = 'instTestMethod'; var DYN_METHOD_NAME = 'dynMethod'; beforeEach(function() { sc = new SharedClass('SomeClass', SomeClass); sm = sc.defineMethod(METHOD_NAME, {isStatic: true}); sm = sc.defineMethod(INST_METHOD_NAME, {isStatic: false}); sc.resolve(function(define) { define(DYN_METHOD_NAME, {isStatic: true}); }); }); it('excludes disabled static methods from the method list', function() { sc.disableMethod(METHOD_NAME, true); var methods = sc.methods().map(getName); expect(methods).to.not.contain(METHOD_NAME); }); it('excludes disabled prototype methods from the method list', function() { sc.disableMethod(INST_METHOD_NAME, false); var methods = sc.methods().map(getName); expect(methods).to.not.contain(INST_METHOD_NAME); }); it('excludes disabled dynamic (resolved) methods from the method list', function() { sc.disableMethod(DYN_METHOD_NAME, true); var methods = sc.methods().map(getName); expect(methods).to.not.contain(DYN_METHOD_NAME); }); }); }); function getName(obj) { return obj.name; } function getFn(obj) { return obj.fn; }