├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── GruntFile.js ├── LICENSE ├── README.md ├── package.json ├── src ├── decorator │ ├── README.md │ ├── component.js │ └── decorator.js ├── delegation │ ├── README.md │ ├── delegate-a.js │ ├── delegate-b.js │ └── delegator.js ├── facade │ ├── README.md │ ├── class-a.js │ ├── class-b.js │ └── facade.js ├── factory-method │ ├── README.md │ ├── factory.js │ └── product.js ├── flyweight │ ├── README.md │ ├── flyweight-factory.js │ └── flyweight.js ├── singleton │ ├── README.md │ └── singleton-example.js └── visitor │ ├── README.md │ ├── element.js │ ├── visitor-a.js │ └── visitor-b.js └── test ├── decorator-spec.js ├── delegation-spec.js ├── facade-spec.js ├── factory-method-spec.js ├── flyweight-spec.js ├── singleton-spec.js └── visitor-spec.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "rules": { 6 | "quotes": [1, "single"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | doc/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.11" 5 | - "0.10" 6 | 7 | addons: 8 | code_climate: 9 | repo_token: df026539a23287b47dd91a6ac6bbb747dba8790e45a85783d613c50dcc31c459 10 | 11 | before_install: 12 | - npm install -g grunt-cli 13 | - npm install -g codeclimate-test-reporter 14 | 15 | install: 16 | - npm install 17 | - grunt 18 | 19 | after_script: 20 | - cat coverage/lcov.info | codeclimate 21 | -------------------------------------------------------------------------------- /GruntFile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 'use strict'; 3 | 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | 7 | jasmine_node: { 8 | options: { 9 | coverage: {}, 10 | forceExit: true, 11 | match: '.', 12 | matchAll: false, 13 | specFolders: ['test'], 14 | extensions: 'js', 15 | specNameMatcher: 'spec', 16 | captureExceptions: true, 17 | junitreport: { 18 | report: false, 19 | savePath : './build/reports/jasmine/', 20 | useDotNotation: true, 21 | consolidate: true 22 | } 23 | }, 24 | src: ['src/**/*.js'] 25 | }, 26 | 27 | eslint: { 28 | options: { 29 | configFile: '.eslintrc', 30 | }, 31 | src: ['src/**/*.js'] 32 | } 33 | }); 34 | 35 | grunt.loadNpmTasks('grunt-jsdoc'); 36 | grunt.config('jsdoc', { 37 | dist : { 38 | src: ['index.js', 'src/**/*.js'], 39 | options: { 40 | destination: 'doc', 41 | readme: 'README.md' 42 | } 43 | } 44 | }); 45 | 46 | var tasks = [ 47 | 'grunt-jasmine-node-coverage', 48 | 'grunt-eslint' 49 | ]; 50 | 51 | for (var i = 0; i < tasks.length; i++) { 52 | grunt.loadNpmTasks(tasks[i]); 53 | } 54 | 55 | grunt.registerTask('default', [ 56 | 'eslint', 57 | 'jsdoc', 58 | 'jasmine_node' 59 | ]); 60 | }; 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Daniel Imms, http://www.growingwiththeweb.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-design-patterns 2 | 3 | [![Build Status](https://travis-ci.org/gwtw/js-design-patterns.svg?branch=master)](http://travis-ci.org/gwtw/js-design-patterns) 4 | 5 | A collection of design pattern *examples* written in JavaScript. These are meant to be used as examples for education and guides for implementing the patterns. 6 | 7 | 8 | 9 | ## License 10 | 11 | MIT © [Daniel Imms](http://www.growingwiththeweb.com) 12 | 13 | 14 | 15 | ## See also 16 | 17 | * [js-data-structures](https://github.com/gwtw/js-data-structures) 18 | * [js-interview-questions](https://github.com/gwtw/js-interview-questions) 19 | * [js-sorting](https://github.com/gwtw/js-sorting) 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-design-patterns", 3 | "version": "1.0.1", 4 | "description": "A collection of design pattern examples written in JavaScript.", 5 | "scripts": { 6 | "test": "jasmine-node ." 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/gwtw/js-design-patterns.git" 11 | }, 12 | "keywords": [ 13 | "design pattern", 14 | "software engineering" 15 | ], 16 | "author": "Daniel Imms (http://www.growingwiththeweb.com)", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/gwtw/js-design-patterns/issues" 20 | }, 21 | "homepage": "https://github.com/gwtw/js-design-patterns", 22 | "devDependencies": { 23 | "grunt": "^0.4.5", 24 | "grunt-eslint": "^17.0.0", 25 | "grunt-jasmine-node-coverage": "^0.4.1", 26 | "grunt-jsdoc": "^1.0.0", 27 | "jasmine-node": "^1.14.3", 28 | "jasmine-reporters": ">=0.2.0 <2.0.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/decorator/README.md: -------------------------------------------------------------------------------- 1 | # Decorator pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2012/11/design-patterns-decorator-pattern.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2012/11/04/decorator-uml.svg) 6 | -------------------------------------------------------------------------------- /src/decorator/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/decorator/component 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Component = function (name) { 8 | this.name = name; 9 | }; 10 | 11 | Component.prototype.operation = function () { 12 | return this.name + ' Component.operation'; 13 | }; 14 | 15 | module.exports = Component; 16 | -------------------------------------------------------------------------------- /src/decorator/decorator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/decorator/decorator 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Decorator = function (component) { 8 | this.component = component; 9 | }; 10 | 11 | Decorator.prototype.operation = function () { 12 | return this.component.name + ' Decorator.operation'; 13 | }; 14 | 15 | module.exports = Decorator; 16 | -------------------------------------------------------------------------------- /src/delegation/README.md: -------------------------------------------------------------------------------- 1 | # Delegation pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2012/07/design-patterns-delegation-pattern.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2012/07/21/delegation-uml.svg) 6 | -------------------------------------------------------------------------------- /src/delegation/delegate-a.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/delegation/delegate-a 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var DelegateA = function () { 8 | return 'a'; 9 | }; 10 | 11 | module.exports = DelegateA; 12 | -------------------------------------------------------------------------------- /src/delegation/delegate-b.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/delegation/delegate-b 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var DelegateB = function () { 8 | return 'b'; 9 | }; 10 | 11 | module.exports = DelegateB; 12 | -------------------------------------------------------------------------------- /src/delegation/delegator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/delegation/delegator 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var DelegateA = require('./delegate-a.js'); 8 | var DelegateB = require('./delegate-b.js'); 9 | 10 | var Delegator = function () { 11 | this.delegate = undefined; 12 | }; 13 | 14 | Delegator.prototype.f = function () { 15 | if (this.delegate) { 16 | return this.delegate(); 17 | } 18 | }; 19 | 20 | Delegator.prototype.toA = function () { 21 | this.delegate = DelegateA; 22 | }; 23 | 24 | Delegator.prototype.toB = function () { 25 | this.delegate = DelegateB; 26 | }; 27 | 28 | module.exports = Delegator; 29 | -------------------------------------------------------------------------------- /src/facade/README.md: -------------------------------------------------------------------------------- 1 | # Facade pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2012/12/design-pattern-facade.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2012/12/15/facade-uml.svg) 6 | -------------------------------------------------------------------------------- /src/facade/class-a.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/facade/class-a 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var ClassA = function () { }; 8 | 9 | ClassA.prototype.operation = function () { 10 | console.log('ClassA'); 11 | }; 12 | 13 | module.exports = ClassA; 14 | -------------------------------------------------------------------------------- /src/facade/class-b.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/facade/class-b 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var ClassB = function () { }; 8 | 9 | ClassB.prototype.operation = function () { 10 | console.log('ClassB'); 11 | }; 12 | 13 | module.exports = ClassB; 14 | -------------------------------------------------------------------------------- /src/facade/facade.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/facade/facade 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var ClassA = require('./class-a.js'); 8 | var ClassB = require('./class-b.js'); 9 | 10 | var Facade = function () { 11 | this.classA = new ClassA(); 12 | this.classB = new ClassB(); 13 | }; 14 | 15 | Facade.prototype.operation = function () { 16 | this.classA.operation(); 17 | this.classB.operation(); 18 | }; 19 | 20 | module.exports = Facade; 21 | -------------------------------------------------------------------------------- /src/factory-method/README.md: -------------------------------------------------------------------------------- 1 | # Factory method pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2012/12/design-pattern-factory-method-pattern.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2012/12/01/factory-method-uml.svg) 6 | -------------------------------------------------------------------------------- /src/factory-method/factory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/factory-method/factory 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Product = require('./product.js'); 8 | 9 | var Factory = function () { }; 10 | 11 | Factory.prototype.makeProduct = function () { 12 | return new Product(); 13 | }; 14 | 15 | module.exports = Factory; 16 | -------------------------------------------------------------------------------- /src/factory-method/product.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/factory-method/product 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Product = function () { }; 8 | 9 | module.exports = Product; 10 | -------------------------------------------------------------------------------- /src/flyweight/README.md: -------------------------------------------------------------------------------- 1 | # Flyweight pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2014/02/flyweight-design-pattern.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2014/02/17/flyweight-uml.svg) 6 | -------------------------------------------------------------------------------- /src/flyweight/flyweight-factory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/flyweight/flyweight-factory 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Flyweight = require('./flyweight.js'); 8 | 9 | var FlyweightFactory = function () { 10 | this.flyweights = {}; 11 | }; 12 | 13 | FlyweightFactory.prototype.get = function (key) { 14 | if (!(key in this.flyweights)) { 15 | this.flyweights[key] = new Flyweight(key); 16 | } 17 | return this.flyweights[key]; 18 | }; 19 | 20 | module.exports = FlyweightFactory; 21 | -------------------------------------------------------------------------------- /src/flyweight/flyweight.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/flyweight/flyweight 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Flyweight = function (intrinisicState) { 8 | this.intrinisicState = intrinisicState; 9 | }; 10 | 11 | Flyweight.prototype.operation = function (extrinsicState) { 12 | // Perform some action using intrinsic and extrinsic state 13 | return this.intrinisicState * extrinsicState; 14 | }; 15 | 16 | module.exports = Flyweight; 17 | -------------------------------------------------------------------------------- /src/singleton/README.md: -------------------------------------------------------------------------------- 1 | # Singleton pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2012/05/design-patterns-singleton.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2012/05/12/singleton-uml.svg) 6 | -------------------------------------------------------------------------------- /src/singleton/singleton-example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/singleton/singleton-example 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var SingletonExample = function () { 8 | if (SingletonExample.prototype.instance) { 9 | return SingletonExample.prototype.instance; 10 | } 11 | SingletonExample.prototype.instance = this; 12 | }; 13 | 14 | module.exports = SingletonExample; 15 | -------------------------------------------------------------------------------- /src/visitor/README.md: -------------------------------------------------------------------------------- 1 | # Visitor pattern 2 | 3 | [Link to article](http://www.growingwiththeweb.com/2014/01/the-visitor-design-pattern.html) 4 | 5 | ![UML Diagram](http://www.growingwiththeweb.com/images/2014/01/06/visitor-uml.svg) 6 | -------------------------------------------------------------------------------- /src/visitor/element.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/visitor/element 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var Element = function () { 8 | this.lastVisitedBy = undefined; 9 | }; 10 | 11 | Element.prototype.accept = function (visitor) { 12 | visitor.visit(this); 13 | }; 14 | 15 | module.exports = Element; 16 | -------------------------------------------------------------------------------- /src/visitor/visitor-a.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/visitor/visitor-a 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var VisitorA = function () { }; 8 | 9 | VisitorA.prototype.visit = function (element) { 10 | element.lastVisitedBy = 'VisitorA'; 11 | }; 12 | 13 | module.exports = VisitorA; 14 | -------------------------------------------------------------------------------- /src/visitor/visitor-b.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/visitor/visitor-b 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | var VisitorB = function () { }; 8 | 9 | VisitorB.prototype.visit = function (element) { 10 | element.lastVisitedBy = 'VisitorB'; 11 | }; 12 | 13 | module.exports = VisitorB; 14 | -------------------------------------------------------------------------------- /test/decorator-spec.js: -------------------------------------------------------------------------------- 1 | var Component = require('../src/decorator/component.js'); 2 | var Decorator = require('../src/decorator/decorator.js'); 3 | 4 | describe('Decorator', function () { 5 | 'use strict'; 6 | 7 | describe('Component.operation', function () { 8 | it('should return the correct string', function () { 9 | var component = new Component('test'); 10 | expect(component.operation()).toBe("test Component.operation"); 11 | }); 12 | }); 13 | 14 | describe('Decorator.operation', function () { 15 | it('should return the correct string', function () { 16 | var component = new Component('test'); 17 | var decorator = new Decorator(component); 18 | expect(decorator.operation()).toBe("test Decorator.operation"); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/delegation-spec.js: -------------------------------------------------------------------------------- 1 | var Delegator = require('../src/delegation/delegator.js'); 2 | 3 | describe('Delegation', function () { 4 | 'use strict'; 5 | 6 | describe('f() without delegate should return undefined', function () { 7 | it('should equal each other', function () { 8 | var delegator = new Delegator(); 9 | expect(delegator.f()).toBe(undefined); 10 | }); 11 | }); 12 | 13 | describe('toA() should return "a"', function () { 14 | it('should equal each other', function () { 15 | var delegator = new Delegator(); 16 | delegator.toA(); 17 | expect(delegator.f()).toBe('a'); 18 | }); 19 | }); 20 | 21 | describe('toB() should return "b"', function () { 22 | it('should equal each other', function () { 23 | var delegator = new Delegator(); 24 | delegator.toB(); 25 | expect(delegator.f()).toBe('b'); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/facade-spec.js: -------------------------------------------------------------------------------- 1 | var Facade = require('../src/facade/facade.js'); 2 | 3 | describe('Facade', function () { 4 | 'use strict'; 5 | 6 | describe('Facade.operation', function () { 7 | var oldConsoleLog; 8 | var output = []; 9 | 10 | beforeEach(function () { 11 | oldConsoleLog = console.log; 12 | console.log = function (text) { 13 | output.push(text); 14 | }; 15 | }); 16 | 17 | afterEach(function () { 18 | console.log = oldConsoleLog; 19 | }); 20 | 21 | it('should call ClassA.operation and ClassB.operation', function () { 22 | var facade = new Facade(); 23 | facade.operation(); 24 | expect(output.length).toBe(2); 25 | expect(output[0]).toBe("ClassA"); 26 | expect(output[1]).toBe("ClassB"); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/factory-method-spec.js: -------------------------------------------------------------------------------- 1 | var Factory = require('../src/factory-method/factory.js'); 2 | var Product = require('../src/factory-method/product.js'); 3 | 4 | describe('Factory method', function () { 5 | 'use strict'; 6 | 7 | describe('Factory', function () { 8 | it('should return the correct product type', function () { 9 | var factory = new Factory(); 10 | var product = factory.makeProduct(); 11 | expect(product instanceof Product).toBe(true); 12 | }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/flyweight-spec.js: -------------------------------------------------------------------------------- 1 | var FlyweightFactory = require('../src/flyweight/flyweight-factory.js'); 2 | 3 | describe('Flyweight', function () { 4 | 'use strict'; 5 | 6 | describe('FlyweightFactory', function () { 7 | it('should cache a single flyweight object', function () { 8 | var flyweightFactory = new FlyweightFactory(); 9 | var flyweight = flyweightFactory.get(1); 10 | expect(flyweight.intrinisicState).toBe(1); 11 | var flyweightSecondGet = flyweightFactory.get(1); 12 | expect(flyweight).toBe(flyweightSecondGet); 13 | }); 14 | 15 | it('should cache multiple flyweight object', function () { 16 | var flyweightFactory = new FlyweightFactory(); 17 | expect(flyweightFactory.get(1)).toBe(flyweightFactory.get(1)); 18 | expect(flyweightFactory.get(2)).toBe(flyweightFactory.get(2)); 19 | expect(flyweightFactory.get(3)).toBe(flyweightFactory.get(3)); 20 | }); 21 | 22 | it('Flyweight.operation should return correct value', function () { 23 | var flyweightFactory = new FlyweightFactory(); 24 | var flyweight = flyweightFactory.get(20); 25 | expect(flyweight.operation(5)).toBe(100); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/singleton-spec.js: -------------------------------------------------------------------------------- 1 | var SingletonExample = require('../src/singleton/singleton-example.js'); 2 | 3 | describe('Singleton', function () { 4 | 'use strict'; 5 | 6 | describe('multiple new calls to SingletonExample', function () { 7 | it('should equal each other', function () { 8 | var a = new SingletonExample(); 9 | var b = new SingletonExample(); 10 | expect(a).toBe(b); 11 | }); 12 | }); 13 | 14 | describe('multiple function calls to SingletonExample', function () { 15 | it('should equal each other', function () { 16 | var a = SingletonExample(); 17 | var b = SingletonExample(); 18 | expect(a).toBe(b); 19 | }); 20 | }); 21 | 22 | describe('function and new calls to SingletonExample', function () { 23 | it('should equal each other', function () { 24 | var a = new SingletonExample(); 25 | var b = SingletonExample(); 26 | expect(a).toBe(b); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/visitor-spec.js: -------------------------------------------------------------------------------- 1 | var Element = require('../src/visitor/element.js'); 2 | var VisitorA = require('../src/visitor/visitor-a.js'); 3 | var VisitorB = require('../src/visitor/visitor-b.js'); 4 | 5 | describe('Visitor', function () { 6 | 'use strict'; 7 | 8 | describe('Element.lastVisitedBy', function () { 9 | it('should not be initialised initially', function () { 10 | var element = new Element(); 11 | expect(typeof element.lastVisitedBy).toBe('undefined'); 12 | }); 13 | }); 14 | 15 | describe('Visiting VisitorA', function () { 16 | it('should set lastVisitedBy', function () { 17 | var element = new Element(); 18 | element.accept(new VisitorA()); 19 | expect(element.lastVisitedBy).toBe('VisitorA'); 20 | }); 21 | }); 22 | 23 | describe('Visiting VisitorB', function () { 24 | it('should set lastVisitedBy', function () { 25 | var element = new Element(); 26 | element.accept(new VisitorB()); 27 | expect(element.lastVisitedBy).toBe('VisitorB'); 28 | }); 29 | }); 30 | 31 | describe('Visiting both visitors', function () { 32 | it('should set lastVisitedBy to the last called', function () { 33 | var element = new Element(); 34 | element.accept(new VisitorA()); 35 | element.accept(new VisitorB()); 36 | expect(element.lastVisitedBy).toBe('VisitorB'); 37 | }); 38 | }); 39 | }); 40 | --------------------------------------------------------------------------------