├── .gitignore ├── .travis.yml ├── karma.conf.js ├── package.json ├── LICENSE ├── README.md ├── tests ├── let_and_const.spec.js ├── Math.spec.js ├── default.spec.js ├── string.spec.js ├── symbols.spec.js ├── arrow_function.spec.js ├── Object.spec.js ├── enhanced_literal.spec.js ├── rest_and_spread.spec.js ├── iterator.spec.js ├── template_strings.spec.js ├── number.spec.js ├── weak-set.spec.js ├── generator.spec.js ├── destructuring.spec.js ├── weak-map.spec.js ├── promises.spec.js ├── set.spec.js ├── class.spec.js ├── Array.spec.js └── map.spec.js └── .eslintrc /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | **/.DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | before_script: 5 | - "npm install" 6 | - "export DISPLAY=:99.0" 7 | - "sh -e /etc/init.d/xvfb start" -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | browsers: ['Firefox'], 4 | files: [ 5 | 'tests/*.spec.js' 6 | ], 7 | frameworks: ['mocha', 'chai'], 8 | preprocessors: { 9 | 'lib/*.js': ['webpack', 'sourcemap'], 10 | 'tests/*.spec.js': ['webpack', 'sourcemap'] 11 | }, 12 | plugins: [ 13 | 'karma-chrome-launcher', 14 | 'karma-firefox-launcher', 15 | 'karma-chai', 16 | 'karma-mocha', 17 | 'karma-sourcemap-loader', 18 | 'karma-webpack', 19 | ], 20 | reporters: ['dots'], 21 | webpack: { 22 | module: { 23 | loaders: [ 24 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime' }, 25 | ], 26 | }, 27 | watch: true, 28 | }, 29 | webpackServer: { 30 | noInfo: true, 31 | }, 32 | }); 33 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-tests", 3 | "version": "0.1.0", 4 | "description": "test suite for es6 features", 5 | "author": "Angus Croll", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/angus-c/es6-tests.git" 10 | }, 11 | "scripts": { 12 | "test": "./node_modules/karma/bin/karma start --single-run", 13 | "testc": "./node_modules/karma/bin/karma start --auto-watch" 14 | }, 15 | "keywords": [ 16 | "es6", 17 | "tests", 18 | "karma", 19 | "mocha", 20 | "chai", 21 | "webpack" 22 | ], 23 | "devDependencies": { 24 | "babel": "^5.1.13", 25 | "babel-core": "^5.1.11", 26 | "babel-loader": "^5.0.0", 27 | "babel-runtime": "^5.1.13", 28 | "eslint": "^0.21.2", 29 | "eslint-plugin-react": "^2.3.0", 30 | "karma": "^0.12.31", 31 | "karma-chai": "^0.1.0", 32 | "karma-chrome-launcher": "^0.1.8", 33 | "karma-firefox-launcher": "^0.1.4", 34 | "karma-mocha": "^0.1.10", 35 | "karma-sourcemap-loader": "^0.3.4", 36 | "karma-webpack": "^1.5.0", 37 | "webpack": "^1.8.9" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 angus croll 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # es6-tests 2 | 3 | [![Build Status](https://secure.travis-ci.org/angus-c/es6-tests.png?branch=master)](http://travis-ci.org/angus-c/es6-tests) 4 | 5 | Unit Tests for every ES6 feature (Work In Progress) 6 | 7 | ##Testing 8 | 9 | ``` 10 | npm test 11 | ``` 12 | ##FAQ 13 | 14 | _Why are some tests skipped?_ 15 | 16 | I'm testing my tests using the wonderful [babel](http://babeljs.io/) transpiler. Their ES6 coverage is excellent [but not yet 100%](http://kangax.github.io/compat-table/es6/#babel). I'm skipping the tests that aren't yet covered so that Travis stays green. 17 | 18 | _There's already an [excellent ES test suite](https://github.com/tc39/test262) Why bother writing another?_ 19 | 20 | I'm certainly not trying to compete with the great work of _test262_. This is purely to improve my own understanding of the ES6 spec – and I figure writing tests from scratch (with no cribbing) is the best way to achieve that. 21 | 22 | _Can I contribute?_ 23 | 24 | I welcome issue reports (I'm sure there are plenty of errors, as I don't have time to be particularly thorough) and please let me know if I've missed any aspects of a new feature. However I'm not accepting Pull Requests for entire features, since I'm doing this for my own education (see above). 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/let_and_const.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-let-and-const-declarations 2 | describe('let and const', () => { 3 | describe('scoping', () => { 4 | it('(they) are scoped once per block', () => { 5 | let a = 3; 6 | const b = 13; 7 | { 8 | let a = 4; 9 | const b = 9; 10 | assert.equal(a, 4); 11 | assert.equal(b, 9); 12 | } 13 | assert.equal(a, 3); 14 | assert.equal(b, 13); 15 | }); 16 | 17 | it('(they) are not available in outer blocks', () => { 18 | { 19 | let a = 4; 20 | const b = 9; 21 | assert.equal(a, 4); 22 | assert.equal(b, 9); 23 | } 24 | assert.throws(() => a, Error); 25 | assert.throws(() => b, Error); 26 | }); 27 | 28 | it('(they) are available in inner blocks', () => { 29 | let a = 3; 30 | const b = 13; 31 | { 32 | assert.equal(a, 3); 33 | assert.equal(b, 13); 34 | } 35 | }); 36 | 37 | it.skip('(let) is not hoisted', () => { 38 | var fn = () => { 39 | a = 3; 40 | let a; 41 | } 42 | assert.throws(fn, Error); 43 | }); 44 | }); 45 | 46 | describe('const and immutability', () => { 47 | it('is mutable', () => { 48 | const x = {a: 4}; 49 | x.a = 7; 50 | x.b = 9; 51 | assert.equal(x.a, 7); 52 | assert.equal(x.b, 9); 53 | }); 54 | 55 | // it('is not reassignable', () => { 56 | // const x = {a: 4}; 57 | // expect(() => {x = {a: 7}}).to.throw(Error); 58 | // expect(() => {x = 'a cake'}).to.throw(Error); 59 | // }); 60 | }); 61 | }); 62 | 63 | -------------------------------------------------------------------------------- /tests/Math.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math 2 | describe('new Math features', () => { 3 | describe('the methods', () => { 4 | it('has Math.sign', () => { 5 | assert.equal(Math.sign(3), 1); 6 | assert.equal(Math.sign(-3), -1); 7 | }); 8 | 9 | it('has Math.trunc', () => { 10 | assert.equal(Math.trunc(1.5), 1); 11 | assert.equal(Math.trunc(-1.7), -1); 12 | assert.equal(Math.trunc(Math.PI), 3); 13 | }); 14 | 15 | it('has Math.cbrt', () => { 16 | assert.equal(Math.cbrt(8), 2); 17 | assert.equal(Math.cbrt(-8), -2); 18 | }); 19 | 20 | it('has Math.log2 and Math.log10', () => { 21 | assert.equal(Math.log2(8), 3); 22 | assert.equal(Math.log10(100), 2); 23 | }); 24 | 25 | it('has Math.fround', () => { 26 | assert.notEqual(Math.fround(1.1), 1.1); 27 | assert.equal(Math.round(Math.fround(1.1)), Math.round(1.1)); 28 | }); 29 | 30 | it('has Math.imul', () => { 31 | assert.notEqual(Math.imul(5, 3.01), 5 * 3.01); 32 | assert.equal(Math.round(Math.imul(5, 3.01)), Math.round(5 * 3.01)); 33 | }); 34 | 35 | it('has Math.clz32', () => { 36 | assert.equal(Math.clz32(58), 26); 37 | }); 38 | 39 | it('has Math.expm1', () => { 40 | assert.closeTo(Math.expm1(1), 1.7182, 0.0001); 41 | }); 42 | 43 | it('has Math.hypot', () => { 44 | assert.equal(Math.hypot(3, 4), 5); 45 | assert.closeTo(Math.hypot(7, 12), 13.8924, 0.0001); 46 | }); 47 | 48 | it('has the new trig functions', () => { 49 | assert.closeTo(Math.sinh(1), 1.1752, 0.0001); 50 | assert.closeTo(Math.cosh(1), 1.5430, 0.0001); 51 | assert.closeTo(Math.tanh(1), 0.7615, 0.0001); 52 | assert.closeTo(Math.asinh(1), 0.8813, 0.0001); 53 | assert.closeTo(Math.acosh(10), 2.9932, 0.0001); 54 | assert.closeTo(Math.atanh(0.5), 0.5493, 0.0001); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /tests/default.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-function-definitions 2 | describe('defaults', () => { 3 | const _n = 2; 4 | const _s = '3'; 5 | const _b = false; 6 | const _sym = Symbol.for('y'); 7 | const _o = {r: 5}; 8 | const _a = [0, 6, 5]; 9 | 10 | it('can assign values of type', () => { 11 | const fn = ( 12 | a = 2, 13 | b = '3', 14 | c = false, 15 | d = Symbol.for('x'), 16 | e = {r: 5}, 17 | f = [0, 6, 5] 18 | ) => { 19 | assert.equal(a, 2); 20 | assert.equal(b, '3'); 21 | assert.equal(c, false); 22 | assert.equal(Symbol.keyFor(d), 'x'); 23 | assert.deepEqual(e, {r: 5}); 24 | assert.sameMembers(f, [0, 6, 5]); 25 | }; 26 | fn(); 27 | }); 28 | 29 | it('can assign via reference', () => { 30 | const fn = ( 31 | a = _n, 32 | b = _s, 33 | c = _b, 34 | d = _sym, 35 | e = _o, 36 | f = _a 37 | ) => { 38 | assert.equal(a, 2); 39 | assert.equal(b, '3'); 40 | assert.equal(c, false); 41 | assert.equal(Symbol.keyFor(d), 'y'); 42 | assert.deepEqual(e, {r: 5}); 43 | assert.sameMembers(f, [0, 6, 5]); 44 | }; 45 | fn(); 46 | }); 47 | 48 | it('only assigns if argument not past', () => { 49 | const fn = ( 50 | a = _n, 51 | b = _s, 52 | c = _b, 53 | d = _sym, 54 | e = _o, 55 | f = _a 56 | ) => { 57 | assert.equal(a, 7); 58 | assert.equal(b, '8'); 59 | assert.equal(c, true); 60 | assert.equal(d, 'not a symbol'); 61 | assert.deepEqual(e, {h: 1}); 62 | assert.equal(f, 73); 63 | }; 64 | fn(7, '8', true, 'not a symbol', {h: 1}, 73); 65 | }); 66 | 67 | it('can be assigned via destructure', () => { 68 | const fn = ( 69 | [a, b, c, d, {e, f}] = [_n, _s, _b, _sym, {e: _o, f: _a}] 70 | ) => { 71 | assert.equal(a, 2); 72 | assert.equal(b, '3'); 73 | assert.equal(c, false); 74 | assert.equal(Symbol.keyFor(d), 'y'); 75 | assert.deepEqual(e, {r: 5}); 76 | assert.sameMembers(f, [0, 6, 5]); 77 | }; 78 | fn(); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /tests/string.spec.js: -------------------------------------------------------------------------------- 1 | describe('new string features', () => { 2 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-source-text 3 | describe('new unicode features', () => { 4 | it('supports new escape syntax', () => { 5 | // surrogate pair and real unicode for a fish 6 | assert.equal('\uD83D\uDC20', '\u{1F420}'); 7 | }); 8 | 9 | it('supports codePointAt', () => { 10 | assert.equal('abc'.codePointAt(1).toString(16), '62'); 11 | assert.equal('\uD83D\uDC20'.codePointAt(0).toString(16), '1f420'); 12 | }); 13 | }); 14 | 15 | describe('new introspect features', () => { 16 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.startswith 17 | it('supports startsWith', () => { 18 | assert.isTrue('panda'.startsWith('p')); 19 | assert.isTrue('panda'.startsWith('panda')); 20 | assert.isFalse('panda'.startsWith('pandas')); 21 | assert.isFalse('panda'.startsWith('q')); 22 | assert.isTrue('\uD83D\uDC20'.startsWith('\u{1F420}')); 23 | }); 24 | 25 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.endswith 26 | it('supports endsWith', () => { 27 | assert.isTrue('panda'.endsWith('a')); 28 | assert.isTrue('panda'.endsWith('panda')); 29 | assert.isFalse('panda'.endsWith('pandas')); 30 | assert.isFalse('panda'.endsWith('q')); 31 | assert.isTrue('\uD83D\uDC20'.endsWith('\u{1F420}')); 32 | }); 33 | 34 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes 35 | it.skip('supports includes', () => { 36 | assert.isTrue('panda'.includes('p')); 37 | assert.isTrue('panda'.includes('n')); 38 | assert.isTrue('panda'.includes('a')); 39 | assert.isTrue('panda'.includes('panda')); 40 | assert.isFalse('panda'.includes('pandas')); 41 | assert.isFalse('panda'.includes('q')); 42 | assert.isTrue('\uD83D\uDC20'.includes('\u{1F420}')); 43 | }); 44 | }); 45 | 46 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.repeat 47 | describe('repeat', () => { 48 | it('supports repeat', () => { 49 | assert.equal('panda'.repeat(3), 'pandapandapanda'); 50 | assert.equal('\uD83D\uDC20'.repeat(2), '\u{1F420}\u{1F420}'); 51 | }); 52 | }); 53 | }); -------------------------------------------------------------------------------- /tests/symbols.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-symbol-objects 2 | describe('Symbols', () => { 3 | describe('data type', () => { 4 | it('has typeof \'symbol\''), () => { 5 | assert.equal(typeof Symbol('x'), 'symbol'); 6 | } 7 | 8 | it.skip('has an arity of 1', () => { 9 | assert.equal(Symbol.length, 1); 10 | }); 11 | 12 | it('does not allow `new` with the constructor', () => { 13 | assert.throws(() => {new Symbol()}, Error); 14 | }); 15 | }); 16 | 17 | describe('uniqueness', () => { 18 | it('is unique without description', () => { 19 | assert.isTrue(Symbol() !== Symbol()); 20 | assert.isTrue(Symbol() != Symbol()); 21 | }); 22 | 23 | it('is unique with same description', () => { 24 | assert.isTrue(Symbol('x') !== Symbol('x')); 25 | assert.isTrue(Symbol('x') != Symbol('x')); 26 | }); 27 | }); 28 | 29 | describe('description property', () => { 30 | it('is added to the GlobalSymbolRegistry', () => { 31 | var s = Symbol.for('x'); 32 | assert.equal(Symbol.keyFor(s), 'x'); 33 | }); 34 | }); 35 | 36 | describe('as object key', () => { 37 | it('can be used as an object key', () => { 38 | let a = Symbol('a') 39 | let obj = { 40 | a: 3 41 | }; 42 | obj[a] = 4; 43 | assert.equal(obj.a, 3); 44 | assert.equal(obj[a], 4); 45 | }); 46 | 47 | it('can be used as an object literal key', () => { 48 | let a = Symbol('a') 49 | let obj = { 50 | a: 3, 51 | [a]: 4 52 | }; 53 | assert.equal(obj.a, 3); 54 | assert.equal(obj[a], 4); 55 | }); 56 | 57 | it('is an ownPropertySymbol', () => { 58 | let a = Symbol('a') 59 | let obj = { 60 | a: 3, 61 | [a]: 4 62 | }; 63 | assert.include(Object.getOwnPropertySymbols(obj), a); 64 | assert.notInclude(Object.keys(obj), a); 65 | assert.notInclude(Object.getOwnPropertyNames(obj), a); 66 | }); 67 | }); 68 | 69 | describe('other qualities', () => { 70 | it('is iterable', () => { 71 | }); 72 | 73 | it('is matchable', () => { 74 | }); 75 | 76 | it('is replaceable', () => { 77 | }); 78 | }); 79 | 80 | describe('well known symbols', () => { 81 | }); 82 | }); 83 | 84 | -------------------------------------------------------------------------------- /tests/arrow_function.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions 2 | describe('arrow functions', () => { 3 | let fn; 4 | describe('braces and return statement', () => { 5 | it('does not need braces or return for single statement', () => { 6 | fn = x => x * x; 7 | assert.equal(fn(4), 16); 8 | }); 9 | 10 | it('needs braces and return for multi statement', () => { 11 | fn = x => {x++; x * x}; 12 | assert.equal(fn(4), undefined); 13 | fn = x => {x++; return x * x}; 14 | assert.equal(fn(4), 25); 15 | }); 16 | }); 17 | 18 | describe('param values', () => { 19 | it('does not need parens for single parameter', () => { 20 | fn = x => x * x; 21 | assert.equal(fn(4), 16); 22 | }); 23 | 24 | it('does need parens for no or many params', () => { 25 | fn = () => 5; 26 | assert.equal(fn(), 5); 27 | fn = (a, b) => a + b; 28 | assert.equal(fn(13, 2), 15); 29 | }); 30 | }); 31 | 32 | describe('`this` value', () => { 33 | it('observes lexical `this` binding', () => { 34 | let obj = { 35 | fn1() { 36 | assert.equal(obj, this); 37 | let fn2 = () => { 38 | assert.equal(obj, this); 39 | [1, 2, 3].forEach(() => { 40 | assert.equal(obj, this); 41 | }); 42 | }; 43 | return fn2(); 44 | } 45 | } 46 | obj.fn1(); 47 | }); 48 | it('will not allow call/apply/bind to change `this`', () => { 49 | let obj = { 50 | fn1() { 51 | assert.equal(obj, this); 52 | let fn2 = () => this; 53 | assert.equal(fn2.call({}), obj); 54 | assert.equal(fn2.apply({}), obj); 55 | assert.equal(fn2.bind({})(), obj); 56 | } 57 | } 58 | obj.fn1(); 59 | }); 60 | }); 61 | 62 | describe.skip('an arrow function is not a full function', () => { 63 | it('has no prototype', () => { 64 | assert.isUndefined((x => x * x).prototype); 65 | }); 66 | 67 | it('is not a constructor', () => { 68 | assert.throw(() => new (x => x * x), Error); 69 | }); 70 | 71 | it('is has no `arguments` object', () => { 72 | (() => assert.isUndefined(arguments))(); 73 | }); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /tests/Object.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object-constructor 2 | describe('ES6 Object constructor methods', () => { 3 | let obj; 4 | beforeEach(() => { 5 | obj = { 6 | a: 47, 7 | b: {c: 4}, 8 | c: true 9 | }; 10 | }); 11 | 12 | // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign 13 | describe('Object.assign', () => { 14 | it('extends existing object', () => { 15 | expect(Object.assign(obj, {d: 4})).to.eql( 16 | {a: 47, b: {c: 4}, c: true, d: 4}); 17 | }); 18 | 19 | it('clobbers existing properties', () => { 20 | expect(Object.assign(obj, {b: {c: 5}})).to.eql( 21 | {a: 47, b: {c: 5}, c: true}); 22 | }); 23 | 24 | it('accepts multiple sources', () => { 25 | expect(Object.assign(obj, {b: {c: 5}}, {d: 4})).to.eql( 26 | {a: 47, b: {c: 5}, c: true, d: 4}); 27 | }); 28 | }); 29 | 30 | // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.is 31 | describe('Object.is', () => { 32 | it('works like === for regular values', () => { 33 | assert.isTrue(Object.is(3, 3)); 34 | assert.isFalse(Object.is('3', 3)); 35 | }); 36 | 37 | it('treats NaNs as equal', () => { 38 | assert.isTrue(Object.is(NaN, NaN)); 39 | }); 40 | 41 | it('treats 0 and -0 as unequal', () => { 42 | assert.isFalse(Object.is(0, -0)); 43 | }); 44 | }); 45 | 46 | // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.setprototypeof 47 | describe('Object.setPrototypeOf', () => { 48 | it('sets prototype of plain object', () => { 49 | Object.setPrototypeOf(obj, {d: 8}); 50 | expect(Object.getPrototypeOf(obj)).to.eql({d: 8}); 51 | assert.equal(obj.d, 8); 52 | }); 53 | 54 | it('replaces prototype of object with custom prototype', () => { 55 | Object.setPrototypeOf(obj, {d: 8}); 56 | expect(Object.getPrototypeOf(obj)).to.eql({d: 8}); 57 | Object.setPrototypeOf(obj, {e: 12}); 58 | expect(Object.getPrototypeOf(obj)).to.eql({e: 12}); 59 | assert.equal(obj.e, 12); 60 | assert.isUndefined(obj.d); 61 | }); 62 | }); 63 | 64 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.getownpropertysymbols 65 | describe('Object.getOwnPropertySymbols', () => { 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /tests/enhanced_literal.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-objects 2 | describe('enhanced literals', () => { 3 | describe('shortcuts', () => { 4 | it('supports all shortcuts', () => { 5 | const a = 1, b = 2; 6 | assert.deepEqual({a, b}, {a: 1, b: 2}); 7 | }); 8 | 9 | it('supports shortcuts mixed with regular assignments', () => { 10 | const a = 1; 11 | assert.deepEqual({a, b: 2}, {a: 1, b: 2}); 12 | }); 13 | }); 14 | describe('computed keys', () => { 15 | it('supports simple string aggregation', () => { 16 | assert.deepEqual({['a' + 'b']: 36}, {ab: 36}); 17 | assert.deepEqual({[['a', 'b'].join('')]: 36}, {ab: 36}); 18 | }); 19 | 20 | it('supports variable substitution', () => { 21 | const x = 'ant', y = 'bee'; 22 | assert.deepEqual({[x]: 36, [y]: 79}, {ant: 36, bee: 79}); 23 | assert.deepEqual({[x + y]: 36, [y]: 79}, {antbee: 36, bee: 79}); 24 | }); 25 | 26 | it('supports function return values', () => { 27 | const fn = (a, b) => '_' + a + a + b; 28 | assert.deepEqual( 29 | {[fn('x', 'y')]: 36, [fn('boo', 'boo')]: 79}, 30 | {_xxy: 36, _boobooboo: 79} 31 | ); 32 | }); 33 | 34 | it('coerces non-strings', () => { 35 | assert.deepEqual( 36 | {[{toString: ()=>'hello'}]: 36, [true]: 79}, 37 | {hello: 36, true: 79} 38 | ); 39 | }); 40 | }); 41 | describe('class-style method syntax', () => { 42 | it('supports class-style method syntax', () => { 43 | const helloer = { 44 | hi() { 45 | return 'hello' 46 | } 47 | }; 48 | assert.equal(helloer.hi(), 'hello'); 49 | }); 50 | 51 | it('can mix old and new method syntax', () => { 52 | const helloer = { 53 | hi() { 54 | return 'hello' 55 | }, 56 | grin: function () { 57 | return 'smile' 58 | } 59 | }; 60 | assert.equal(helloer.hi(), 'hello'); 61 | assert.equal(helloer.grin(), 'smile'); 62 | }); 63 | }); 64 | describe('prototype assignment', () => { 65 | it('can assign prototype to instance', () => { 66 | const thing = { 67 | __proto__: { 68 | do() {return 'superDo'} 69 | } 70 | }; 71 | assert.isFalse(thing.hasOwnProperty('do')); 72 | assert.equal(thing.do(), 'superDo'); 73 | assert.isUndefined(thing.constructor.prototype.do); 74 | }); 75 | 76 | it('supports super', () => { 77 | const thing = { 78 | do() { 79 | return 'meDo' + '@' + super.do(); 80 | }, 81 | __proto__: { 82 | do() {return 'superDo'} 83 | } 84 | }; 85 | assert.isTrue(thing.hasOwnProperty('do')); 86 | assert.equal(thing.do(), 'meDo@superDo'); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /tests/rest_and_spread.spec.js: -------------------------------------------------------------------------------- 1 | describe('rest and spread', () => { 2 | describe('rest', () => { 3 | it('makes an array', () => { 4 | ((...args) => { 5 | assert.isTrue(Array.isArray(args)); 6 | })(1, 2, 3); 7 | }); 8 | 9 | it('includes all arguments', () => { 10 | ((...args) => { 11 | assert.sameMembers(args, ['one', 2, false]); 12 | })('one', 2, false); 13 | ((...args) => { 14 | assert.deepEqual(args[0], {a: {b:4}}); 15 | })({a: {b:4}}); 16 | }); 17 | 18 | it('returns an empty array if no arguments', () => { 19 | ((...args) => { 20 | assert.sameMembers(args, []); 21 | })(); 22 | }); 23 | 24 | it('is only composed of the params not assigned to named args', () => { 25 | ((a, b, ...args) => { 26 | assert.sameMembers(args, [3, 4, 5]); 27 | })(1, 2, 3, 4, 5); 28 | }); 29 | 30 | it('is empty if all param are assigned to named args', () => { 31 | ((a, b, ...args) => { 32 | assert.sameMembers(args, []); 33 | })(1, 2); 34 | }); 35 | 36 | // it('must fall after named args', () => { 37 | // assert.throws((a, b, ...args, c) => {}, Error); 38 | // }); 39 | 40 | it('can destructure', () => { 41 | ((a, b, ...[c, d]) => { 42 | assert.equal(c, 3); 43 | assert.equal(d, 4); 44 | })(1, 2, 3, 4); 45 | ((a, b, ...[c, d]) => { 46 | assert.equal(c, 3); 47 | assert.isUndefined(d); 48 | })(1, 2, 3); 49 | ((a, b, ...[c, d]) => { 50 | assert.equal(c, 3); 51 | assert.equal(d, 4); 52 | })(1, 2, 3, 4, 5, 6); 53 | }); 54 | 55 | it('can be used to destructure within an array', () => { 56 | ((a, b, ...c) => { 57 | assert.sameMembers(c, [3, 4]); 58 | })(1, 2, 3, 4); 59 | }); 60 | }); 61 | 62 | describe('spread', () => { 63 | // it('cannot exist standalone', () => { 64 | // expect((a)=>{...a}).toThrow(Error); 65 | // }); 66 | 67 | it('creates as many items as array had members', () => { 68 | assert.equal([...[1, 2, 3]].length, 3); 69 | }); 70 | 71 | it('generates same items as array', () => { 72 | assert.sameMembers([...[1, 2, 3]], [1, 2, 3]); 73 | }); 74 | 75 | it('generates no members from an empty array', () => { 76 | assert.equal([...[]].length, 0); 77 | assert.sameMembers([...[]], []); 78 | }); 79 | 80 | it('need not come last in an array', () => { 81 | assert.equal([1, ...[2, 3, 4], 5].length, 5); 82 | assert.sameMembers([1, ...[2, 3, 4], 5], [1, 2, 3, 4, 5]); 83 | }); 84 | 85 | it('can be used to make arguments', () => { 86 | let arr = [1, 2, 3]; 87 | arr.push(...[4, 5, 6]); 88 | assert.sameMembers(arr, [1, 2, 3, 4, 5, 6]); 89 | }); 90 | 91 | it('can be used to spread iterables', () => { 92 | }); 93 | }); 94 | }); 95 | 96 | -------------------------------------------------------------------------------- /tests/iterator.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-operations-on-iterator-objects 2 | describe('iterators', () => { 3 | const arrayLikeIterables = [ 4 | [1, 2, 3], 5 | 'abc' 6 | ]; 7 | const mapLikeIterables = [ 8 | [1, 2, 3].keys(), 9 | [1, 2, 3].entries(), 10 | new Map([[1, 'one'], [2, 'two']]), 11 | new Set([1, 2, 2, 4])/*, 12 | document.body */ 13 | ]; 14 | const allIterables = arrayLikeIterables.concat(mapLikeIterables); 15 | 16 | describe('Symbol.iterator', () => { 17 | const s = Symbol.iterator; 18 | 19 | it.skip('is a symbol', () => { 20 | assert.equal(typeof s, 'symbol'); 21 | }); 22 | 23 | it('(allIterables) have a `Symbol.iterator` method', () => { 24 | allIterables.forEach((iterable) => { 25 | assert.equal(typeof iterable[Symbol.iterator](), 'object'); 26 | }); 27 | (function () { 28 | assert.equal(typeof arguments[Symbol.iterator](), 'object'); 29 | })(1, 2, 3); 30 | }); 31 | }); 32 | 33 | describe('next()', () => { 34 | let iterator, next, count; 35 | 36 | it('works with for arrayLikeIterables', () => { 37 | arrayLikeIterables.forEach((iterable) => { 38 | iterator = iterable[Symbol.iterator](); 39 | count = 0; 40 | while ((next = iterator.next().value) != null) { 41 | assert(next, iterable[count++]); 42 | count++; 43 | } 44 | }); 45 | }); 46 | 47 | it('works with for mapLikeIterables', () => { 48 | mapLikeIterables.forEach((iterable) => { 49 | let toArray = [...iterable]; 50 | iterator = iterable[Symbol.iterator](); 51 | count = 0; 52 | while ((next = iterator.next().value) != null) { 53 | assert(next, toArray[count++]); 54 | count++; 55 | } 56 | }); 57 | }); 58 | 59 | it('returns done when no more items', () => { 60 | allIterables.forEach((iterable) => { 61 | iterator = iterable[Symbol.iterator](); 62 | while (next = iterator.next(), next.value != null); 63 | assert.deepEqual(next, {value: undefined, done: true}); 64 | }); 65 | }); 66 | }); 67 | 68 | describe('for-of', () => { 69 | let count; 70 | it('works for arrayLikeIterables', () => { 71 | arrayLikeIterables.forEach((iterable) => { 72 | count = 0; 73 | for (let x of iterable) { 74 | assert.equal(x, iterable[count++]); 75 | } 76 | }); 77 | }); 78 | 79 | it('works for mapLikeIterables', () => { 80 | mapLikeIterables.forEach((iterable) => { 81 | let toArray = [...iterable]; 82 | count = 0; 83 | for (let x of iterable) { 84 | if (typeof x == 'object') { 85 | assert.sameMembers(x, toArray[count++]); 86 | } else { 87 | assert.equal(x, toArray[count++]); 88 | } 89 | } 90 | }); 91 | }); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /tests/template_strings.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-static-semantics-tv-s-and-trv-s 2 | describe('template strings', () => { 3 | describe('basic strings', () => { 4 | it('generates a string', () => { 5 | assert.equal(typeof `hello`, 'string'); 6 | assert.equal(`hello`, 'hello'); 7 | }); 8 | 9 | it('can be multiline', () => { 10 | assert.equal(typeof `hello 11 | how are you`, 'string'); 12 | assert.equal(`hello 13 | how are you`, 'hello\n' + 14 | 'how are you'); 15 | }); 16 | }); 17 | describe('interpolation', () => { 18 | it('can insert primitive variables', () => { 19 | const a = 3; 20 | const b = 'fifty'; 21 | const c = true; 22 | assert.equal(`the ${c} price is ${a} dollars and ${b} cents`, 23 | 'the true price is 3 dollars and fifty cents'); 24 | }); 25 | 26 | it('can insert object variables', () => { 27 | const a = {toString: () => 'an object'}; 28 | const b = [1, 2, 3]; 29 | b.toString = () => 'an array' 30 | assert.equal(`${a} and ${b}`, 31 | 'an object and an array'); 32 | }); 33 | 34 | it('can insert expressions', () => { 35 | assert.equal(`${2**2} and ${((a, b)=>3 + a/b)(6, 2)}`, 36 | '4 and 6'); 37 | }); 38 | }); 39 | describe('tag functions', () => { 40 | const a = 3; 41 | const b = {x: 4, y: a}; 42 | 43 | it('(its) first arg is an array of the strings literals ', () => { 44 | assert.isTrue(Array.isArray(((strs)=>strs)`hello`)); 45 | assert.equal(((strs)=>strs.length)`hello`, 1); 46 | assert.equal(((strs)=>strs[0])`hello`, 'hello'); 47 | assert.equal(((strs)=>strs.length)`hello ${a}`, 2); 48 | assert.equal(((strs)=>strs[0])`hello ${a}`, 'hello '); 49 | assert.equal(((strs)=>strs[1])`hello ${a}`, ''); 50 | assert.equal(((strs)=>strs.length)`hello ${a} goodbye`, 2); 51 | assert.equal(((strs)=>strs[0])`hello ${a} goodbye`, 'hello '); 52 | assert.equal(((strs)=>strs[1])`hello ${a} goodbye`, ' goodbye'); 53 | }); 54 | 55 | it('(its) first arg has a `raw` property', () => { 56 | assert.isTrue(Array.isArray(((strs)=>strs.raw)`hello`)); 57 | assert.equal(((strs)=>strs.raw.length)`hello`, 1); 58 | assert.equal(((strs)=>strs.raw[0])`hello`, `hello`); 59 | assert.equal(((strs)=>strs.raw.length)`hello ${a}`, 2); 60 | assert.equal(((strs)=>strs.raw[0])`hello ${a}`, 'hello '); 61 | assert.equal(((strs)=>strs.raw[1])`hello ${a}`, ''); 62 | assert.equal(((strs)=>strs.raw.length)`hel 63 | lo`, 1); 64 | assert.equal(((strs)=>strs.raw[0])`hel 65 | lo`, 'hel\nlo'); 66 | }); 67 | 68 | it('(its) remaining args are the interpolated values ', () => { 69 | assert.equal(((strs, ...values)=>values.length)`hello`, 0); 70 | assert.equal(((strs, ...values)=>values.length)`hello ${a}`, 1); 71 | assert.equal(((strs, ...values)=>values[0])`hello ${a}`, 3); 72 | assert.equal(((strs, ...values)=>values.length)`hello ${a} goodbye ${b}`, 2); 73 | assert.equal(((strs, ...values)=>values[0])`hello ${a} goodbye ${b}`, 3); 74 | assert.deepEqual(((strs, ...values)=>values[1])`hello ${a} goodbye ${b}`, {x: 4, y: a}); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /tests/number.spec.js: -------------------------------------------------------------------------------- 1 | describe('new number features', () => { 2 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-additional-syntax-numeric-literals 3 | describe('base n literals', () => { 4 | it('supports binary literals', () => { 5 | assert.equal(0b10101, 21); 6 | }); 7 | 8 | it('supports octal literals', () => { 9 | assert.equal(0o1234567, 342391); 10 | }); 11 | }); 12 | describe('new static functions', () => { 13 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite 14 | it('has Number.isFinite', () => { 15 | assert.equal(Number.isFinite(Number.Infinity), false); 16 | assert.equal(Number.isFinite(0), true); 17 | assert.equal(Number.isFinite('a'), false); 18 | assert.equal(Number.isFinite(77), true); 19 | // compare with global fn... 20 | assert.equal(isFinite('35'), true); 21 | assert.equal(Number.isFinite('35'), false); 22 | }); 23 | 24 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isnan 25 | it('has Number.isNaN', () => { 26 | assert.equal(Number.isNaN(12), false); 27 | assert.equal(Number.isNaN('x'), false); 28 | assert.equal(Number.isNaN(NaN), true); 29 | }); 30 | 31 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isinteger 32 | it('has Number.isInteger', () => { 33 | // assert.isFalse(Number.isInteger(0.5)); 34 | assert.isTrue(Number.isInteger(1)); 35 | assert.isFalse(Number.isInteger('q')); 36 | assert.isFalse(Number.isInteger(NaN)); 37 | }); 38 | 39 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.issafeinteger 40 | it('has Number.isSafeInteger', () => { 41 | const safe1 = Math.pow(2, 53) - 1; 42 | const unsafe1 = Math.pow(2, 53); 43 | const safe2 = 1 - Math.pow(2, 53); 44 | const unsafe2 = -Math.pow(2, 53); 45 | assert.isTrue(Number.isSafeInteger(safe1)); 46 | assert.isFalse(Number.isSafeInteger(unsafe1)); 47 | assert.isTrue(Number.isSafeInteger(safe2)); 48 | assert.isFalse(Number.isSafeInteger(unsafe2)); 49 | assert.isTrue(Number.isSafeInteger(7)); 50 | assert.isFalse(Number.isSafeInteger(7.1)); 51 | assert.isTrue(Number.isSafeInteger(0)); 52 | assert.isFalse(Number.isSafeInteger(1 / 4)); 53 | }); 54 | }); 55 | describe('new static values', () => { 56 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.epsilon 57 | it('defines Number.EPSILON', () => { 58 | // EPSILON is approx 2.2204460492503130808472633361816 x 10‍−‍16. 59 | assert.isDefined(Number.EPSILON); 60 | assert.isFalse((0.3 - (0.2 + 0.1)) === 0); 61 | assert.isTrue((0.3 - (0.2 + 0.1)) < Number.EPSILON); 62 | assert.isTrue((0.3 - (0.2 + 0.1)) > -Number.EPSILON); 63 | }); 64 | 65 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer 66 | it('defines Number.MAX_SAFE_INTEGER', () => { 67 | assert.isDefined(Number.MAX_SAFE_INTEGER); 68 | assert.equal(Number.MAX_SAFE_INTEGER, Math.pow(2, 53) - 1); 69 | }); 70 | 71 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.min_safe_integer 72 | it('defines Number.MIN_SAFE_INTEGER', () => { 73 | assert.isDefined(Number.MIN_SAFE_INTEGER); 74 | assert.equal(Number.MIN_SAFE_INTEGER, 1 - Math.pow(2, 53)); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /tests/weak-set.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-weakset-objects 2 | describe('weak sets', () => { 3 | describe('types', () => { 4 | it('(WeakSet) is a constructor', () => { 5 | assert.equal(typeof WeakSet, 'function'); 6 | assert.isDefined(WeakSet.prototype); 7 | }); 8 | 9 | it('(weak set instance) is an object', () => { 10 | assert.equal(typeof new WeakSet(), 'object'); 11 | }); 12 | }); 13 | 14 | describe('constructor parameter', () => { 15 | it('accepts null or nothing', () => { 16 | assert.isDefined(new WeakSet(null)); 17 | assert.isDefined(new WeakSet()); 18 | }); 19 | 20 | it('accepts any non-primitive iterable type', () => { 21 | const iterables = [ 22 | [[], {}, () => {}], 23 | new Set([[], {}, () => {}]), 24 | [[], {}, () => {}].entries() 25 | ]; 26 | 27 | iterables.forEach((iterable) => { 28 | assert.isDefined(new WeakSet(iterable)); 29 | }); 30 | }); 31 | 32 | it('accepts any non-primitive value types', () => { 33 | const iterables = [ 34 | [[], {}, () => {}], 35 | [new Map(), new Set(), new WeakMap(), new WeakSet()] 36 | ]; 37 | 38 | iterables.forEach((iterable) => { 39 | const set = new WeakSet(iterable); 40 | assert.isDefined(set); 41 | iterable.forEach((value) => { 42 | assert.isTrue(set.has(value)); 43 | }); 44 | }); 45 | }); 46 | 47 | it('does not accept primitive value types', () => { 48 | assert.throws( 49 | () => { new WeakSet([1, false, 'a'])}, 50 | Error 51 | ); 52 | }); 53 | }); 54 | 55 | describe('weakset.add', () => { 56 | it('is a method', () => { 57 | const weakset = new WeakSet(); 58 | assert.isDefined(weakset.add); 59 | assert.equal(typeof weakset.add, 'function'); 60 | }); 61 | 62 | it('adds values to a weakset', () => { 63 | const weakset = new WeakSet(); 64 | const values = [{}, [], () => {}, [], {}]; 65 | values.forEach(value => { 66 | weakset.add(value); 67 | }); 68 | values.forEach(value => { 69 | assert.isTrue(weakset.has(value)); 70 | }); 71 | }); 72 | }); 73 | 74 | describe('weakset.delete()', () => { 75 | it('defines `delete`', () => { 76 | assert.equal(typeof new WeakSet().delete, 'function'); 77 | }); 78 | 79 | it('(`weakset.delete`) deletes the specified key', () => { 80 | const obj = {}, arr = [], fn = () => {}; 81 | const values = [obj, arr, fn]; 82 | const weakset = new WeakSet(values); 83 | assert.isTrue(weakset.has(obj)); 84 | weakset.delete(obj); 85 | assert.isFalse(weakset.has(obj)); 86 | }); 87 | }); 88 | 89 | describe('de-duping', () => { 90 | it('removes duplicate values', () => { 91 | const obj = {}, arr = [], fn = () => {}; 92 | const values = [obj, obj, arr, fn, obj, fn]; 93 | const weakset = new WeakSet(values); 94 | // only test is deletion since we can't iterate weak collection values 95 | weakset.delete(fn); 96 | assert.isFalse(weakset.has(fn)); 97 | }); 98 | }); 99 | 100 | describe('transient keys', () => { 101 | it('(its) keys are GCed when they have no other refs', () => { 102 | // untestable 103 | }); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /tests/generator.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generator-objects 2 | describe('generators', () => { 3 | describe('types', () => { 4 | it.skip('(GeneratorFunction) is a constructor', () => { 5 | assert.equal(typeof GeneratorFunction, 'function'); 6 | assert.equal(typeof GeneratorFunction.prototype, 'object'); 7 | }); 8 | 9 | it.skip('function* is a function keyword', () => { 10 | assert.equal(typeof function* () {}, 'function'); 11 | }); 12 | }); 13 | 14 | describe('yield', () => { 15 | it('exits the function', () => { 16 | let x = 0; 17 | const g = (function* () { 18 | while (true) { 19 | x++; 20 | yield; 21 | } 22 | })(); 23 | assert.deepEqual(g.next(), {value: undefined, done: false}); 24 | assert.equal(x, 1); 25 | }); 26 | 27 | it('exits the function with the given value', () => { 28 | let x = 0; 29 | const g = (function* () { 30 | while (true) { 31 | x++; 32 | yield 7; 33 | } 34 | })(); 35 | assert.deepEqual(g.next(), {value: 7, done: false}); 36 | assert.equal(x, 1); 37 | }); 38 | 39 | it('maintains lcoal state between calls', () => { 40 | let x = 0, y; 41 | const g = (function* () { 42 | while (true) { 43 | x++; 44 | if (x == 1) { 45 | y = 8; 46 | } 47 | yield; 48 | } 49 | })(); 50 | assert.deepEqual(g.next(), {value: undefined, done: false}); 51 | assert.equal(x, 1); 52 | assert.equal(y, 8); 53 | assert.deepEqual(g.next(), {value: undefined, done: false}); 54 | assert.equal(x, 2); 55 | assert.equal(y, 8); 56 | }); 57 | 58 | it('yields while valid loop', () => { 59 | let x = 0; 60 | const g = (function* () { 61 | while (x < 2) { 62 | x++; 63 | yield; 64 | } 65 | })(); 66 | assert.deepEqual(g.next(), {value: undefined, done: false}); 67 | assert.equal(x, 1); 68 | assert.deepEqual(g.next(), {value: undefined, done: false}); 69 | assert.equal(x, 2); 70 | assert.deepEqual(g.next(), {value: undefined, done: true}); 71 | }); 72 | 73 | it('delegates to another generator', () => { 74 | function* gf(y = 0) { 75 | while (true) { 76 | x -= 10; 77 | x += y; 78 | yield; 79 | } 80 | } 81 | 82 | let x = 0; 83 | const g1 = (function* () { 84 | while (true) { 85 | x++; 86 | yield* gf(); 87 | yield; 88 | } 89 | })(); 90 | assert.deepEqual(g1.next(), {value: undefined, done: false}); 91 | assert.equal(x, -9); 92 | 93 | x = 0; 94 | const g2 = (function* () { 95 | while (true) { 96 | x++; 97 | yield* gf(4); 98 | yield; 99 | } 100 | })(); 101 | assert.deepEqual(g2.next(), {value: undefined, done: false}); 102 | assert.equal(x, -5); 103 | }); 104 | }); 105 | 106 | describe('for...of over generators', () => { 107 | it('iterates over the generator', () => { 108 | let x = 0; 109 | const g = function* () { 110 | while (true) { 111 | x++; 112 | yield x; 113 | } 114 | }; 115 | 116 | let tally = 0; 117 | for (let val of g()) { 118 | if (val > 5) { 119 | break; 120 | } 121 | tally += val; 122 | } 123 | assert.equal(tally, 1 + 2 + 3 + 4 + 5); 124 | }); 125 | }); 126 | }); 127 | 128 | -------------------------------------------------------------------------------- /tests/destructuring.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-destructuring-assignment 2 | describe('destructuring', () => { 3 | let array1 = [1, 3, 5, 2, 4]; 4 | let array2 = [{a: 4, b: true}, [1, 2], undefined, false, 'c']; 5 | describe('arrays', () => { 6 | it('assigns all values', () => { 7 | let [a, b, c, d, e] = array1; 8 | assert.equal(a, 1); 9 | assert.equal(b, 3); 10 | assert.equal(c, 5); 11 | assert.equal(d, 2); 12 | assert.equal(e, 4); 13 | let [f, g, h, i, j] = array2; 14 | assert.deepEqual(f, {a: 4, b: true}); 15 | assert.sameMembers(g, [1, 2]); 16 | assert.isUndefined(h); 17 | assert.isFalse(i); 18 | assert.equal(j, 'c'); 19 | }); 20 | 21 | it('assigns to named variables only', () => { 22 | let [c, d] = array1; 23 | assert.equal(c, 1); 24 | assert.equal(d, 3); 25 | let [,, e, f, g] = array1; 26 | assert.equal(e, 5); 27 | assert.equal(f, 2); 28 | assert.equal(g, 4); 29 | }); 30 | 31 | it('assigns to rest variables', () => { 32 | let [a, ...rest] = array1; 33 | assert.equal(a, 1); 34 | assert.sameMembers(rest, [3, 5, 2, 4]); 35 | [...rest] = array1; 36 | assert.sameMembers(rest, [1, 3, 5, 2, 4]); 37 | }); 38 | }); 39 | describe('objects', () => { 40 | let obj = { 41 | a: 1, 42 | b: [2, 3, 4], 43 | c: {cc: 4, dd: {eee: 'hello'}}, 44 | d: true 45 | } 46 | 47 | it('assigns top level keys', () => { 48 | let {a, b, c, d} = obj; 49 | assert.equal(a, 1); 50 | assert.sameMembers(b, [2, 3, 4]); 51 | assert.deepEqual(c, {cc: 4, dd: {eee: 'hello'}}); 52 | assert.isTrue(d); 53 | }); 54 | 55 | it('assigns selected keys', () => { 56 | let {a, d} = obj; 57 | assert.equal(a, 1); 58 | assert.isTrue(d); 59 | }); 60 | 61 | it('assigns deep nested values', () => { 62 | let {a: x, c: {dd: {eee: y}}, d: z} = obj; 63 | assert.equal(x, 1); 64 | assert.equal(y, 'hello'); 65 | assert.isTrue(z); 66 | }); 67 | }); 68 | describe('with primitives', () => { 69 | it('assigns undefined if RHS is primitive', () => { 70 | let {x, y, z} = 4; 71 | assert.isUndefined(x); 72 | assert.isUndefined(y); 73 | assert.isUndefined(z); 74 | }); 75 | }); 76 | describe('with defaults', () => { 77 | it('can use defaults', () => { 78 | let {a = 1, b = 2, c = 3, d = 4} = {b: 3, d: 1}; 79 | assert.equal(a, 1); 80 | assert.equal(b, 3); 81 | assert.equal(c, 3); 82 | assert.equal(d, 1); 83 | }); 84 | }); 85 | describe('as', () => { 86 | it('can reassign', () => { 87 | let a, b, c; 88 | let {a: x, b: y, c: z, d} = {a: 2, b: 3, c: 4, d: 1}; 89 | assert.equal(x, 2); 90 | assert.equal(y, 3); 91 | assert.equal(z, 4); 92 | assert.isUndefined(a); 93 | assert.isUndefined(b); 94 | assert.isUndefined(c); 95 | assert.equal(d, 1); 96 | }); 97 | }); 98 | describe('in arguments', () => { 99 | it('can be used in arguments', () => { 100 | let fn = (i, {a: x, c: {dd: {eee: y}}, d: z}) => { 101 | assert.equal(i, 5); 102 | assert.equal(x, 1); 103 | assert.equal(y, 'hello'); 104 | assert.equal(z, true); 105 | } 106 | fn(5, {a: 1, c: {cc: 4, dd: {eee: 'hello'}}, d: true}); 107 | }) 108 | }); 109 | describe('in for-of', () => { 110 | it('can destructure a for-of', () => { 111 | let arr = [{a: 4, b: 7}, {a: 8, b: 3}, {a: 6, b: 2}]; 112 | let count = 0; 113 | for (let {a, b} of arr) { 114 | assert.equal(a, arr[count].a); 115 | assert.equal(b, arr[count].b); 116 | count++; 117 | } 118 | }); 119 | }); 120 | }); 121 | -------------------------------------------------------------------------------- /tests/weak-map.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-weakmap-objects 2 | describe('weak maps', () => { 3 | describe('types', () => { 4 | it('(WeakMap) is a constructor', () => { 5 | assert.equal(typeof WeakMap, 'function'); 6 | assert.isDefined(WeakMap.prototype); 7 | }); 8 | 9 | it('(weak map instance) is an object', () => { 10 | assert.equal(typeof new WeakMap(), 'object'); 11 | }); 12 | }); 13 | describe('constructor parameter', () => { 14 | it('accepts null or nothing', () => { 15 | assert.isDefined(new WeakMap(null)); 16 | assert.isDefined(new WeakMap()); 17 | }); 18 | 19 | it('accepts any key-value iterable', () => { 20 | const keyValueIterables = [ 21 | [[{}, 1], [[], 2]], 22 | new Map([[{}, 1], [[], 2]]), 23 | new Set([[{}, 1], [[], 2]]) 24 | ]; 25 | keyValueIterables.forEach((iterable) => { 26 | assert.isDefined(new WeakMap(iterable)); 27 | }); 28 | }); 29 | 30 | it('accepts any type of values', () => { 31 | const keyValueIterables = [ 32 | [[{}, 1], [[], 2]], 33 | [[{}, 'a'], [[], 'b']], 34 | [[{}, []], [[], []]], 35 | [[{}, {}], [[], {}]], 36 | [[{}, 1], [[], 0]], 37 | [[{}, Symbol(4)], [[], Symbol(2)]], 38 | [[{}, new Map([['2', 5]])], [[], new Map([['7', 8]])]] 39 | ]; 40 | keyValueIterables.forEach((iterable, c) => { 41 | const weakMap = new WeakMap(iterable); 42 | assert.isDefined(weakMap); 43 | [0, 1].forEach((i) => { 44 | assert.equal( 45 | weakMap.get(keyValueIterables[c][i][0]), 46 | keyValueIterables[c][i][1] 47 | ); 48 | }); 49 | }); 50 | }); 51 | 52 | it('accepts any type of object as key', () => { 53 | const keyValueIterables = [ 54 | [[{}, 1], [new Date(), 1]], 55 | [[[], 1], [{}, 1]], 56 | [[()=>{}, 1], [[], 1]], 57 | [[new Map(), 1], [()=>{}, 1]], 58 | [[new Set(), 1], [new Map(), 1]], 59 | [[new WeakMap(), 1], [new Set(), 1]], 60 | [[new Date(), 1], [new WeakMap(), 1]] 61 | ]; 62 | 63 | keyValueIterables.forEach((iterable, c) => { 64 | const weakMap = new WeakMap(iterable); 65 | assert.isDefined(weakMap); 66 | [0, 1].forEach((i) => { 67 | assert.equal( 68 | weakMap.get(keyValueIterables[c][i][0]), 69 | keyValueIterables[c][i][1] 70 | ); 71 | }); 72 | }); 73 | }); 74 | 75 | it('does not accept primitives as keys', () => { 76 | const keyValueIterables = [ 77 | [[1, 1], [2, 1]], 78 | [['a', 1], ['b', 1]], 79 | [[true, 1], [false, 1]], 80 | ]; 81 | 82 | keyValueIterables.forEach((iterable, c) => { 83 | assert.throws(()=>{const weakMap = new WeakMap(iterable)}, Error); 84 | }); 85 | }); 86 | }); 87 | 88 | describe('`set` method', () => { 89 | it('can be updated using `set`', () => { 90 | const keys = [{}, [], ()=>{}, new Map(), new Set(), new WeakMap(), new Date()]; 91 | const values = [1, 'a', false, Symbol(), new Date(), {}, []]; 92 | const weakMap = new WeakMap(); 93 | keys.forEach((key, i) => { 94 | weakMap.set(key, values[i]); 95 | }); 96 | keys.forEach((key, i) => { 97 | assert.equal(weakMap.get(keys[i]), values[i]); 98 | }); 99 | }); 100 | }); 101 | 102 | describe('`has` method', () => { 103 | it('checks if key is present', () => { 104 | const keys = [{}, [], ()=>{}, new Map(), new Set(), new WeakMap(), new Date()]; 105 | const values = [1, 'a', false, Symbol(), new Date(), {}, []]; 106 | const weakMap = new WeakMap(); 107 | keys.forEach((key, i) => { 108 | weakMap.set(key, values[i]); 109 | }); 110 | keys.forEach((key, i) => { 111 | assert.isTrue(weakMap.has(keys[i])); 112 | }); 113 | }); 114 | }); 115 | 116 | describe('weakMap.delete()', () => { 117 | it('defines `delete`', () => { 118 | assert.equal(typeof new WeakMap().delete, 'function'); 119 | }); 120 | 121 | it('(`weakMap.delete`) deletes the specified key', () => { 122 | const key1 = {}; 123 | const key2 = {}; 124 | const weakMap = new WeakMap([[key1, 1], [key2, 2]]); 125 | assert.isTrue(weakMap.has(key1)); 126 | weakMap.delete(key1); 127 | assert.isFalse(weakMap.has(key1)); 128 | }); 129 | }); 130 | 131 | describe('transient keys', () => { 132 | it('(its) keys are GCed when they have no other refs', () => { 133 | // untestable 134 | }); 135 | }); 136 | }); -------------------------------------------------------------------------------- /tests/promises.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects 2 | describe('Promises', () => { 3 | function getPromise(success) { 4 | return new Promise((resolve, reject) => { 5 | setTimeout( 6 | success ? resolve('success') : reject('failure'), 7 | (Math.random() + 1) * 1000 8 | ); 9 | }); 10 | } 11 | 12 | describe('data types', () => { 13 | it('is a constructor', () => { 14 | assert.equal(typeof Promise, 'function'); 15 | assert.equal(typeof Promise.prototype, 'object'); 16 | assert.isTrue(new Promise((res, rej) => {}) instanceof Promise); 17 | assert.equal(typeof new Promise((res, rej) => {}), 'object'); 18 | }); 19 | 20 | it('requires a function argument', () => { 21 | assert.throws(() => new Promise(), Error); 22 | assert.doesNotThrow(() => new Promise((res, rej) => {})); 23 | assert.throws(() => new Promise({}), Error); 24 | }); 25 | }); 26 | 27 | describe('timing', () => { 28 | it('is async', (done) => { 29 | let buffer = []; 30 | new Promise( 31 | (resolve) => { 32 | resolve(); 33 | buffer.push('hello'); 34 | } 35 | ).then(() => { 36 | buffer.push('goodbye'); 37 | assert.equal(buffer[0], 'hello'); 38 | assert.equal(buffer[1], 'goodbye'); 39 | done(); 40 | }); 41 | assert.equal(buffer[0], 'hello'); 42 | assert.equal(buffer[1], undefined); 43 | }); 44 | }); 45 | 46 | describe('resolve and reject', () => { 47 | it('calls resolve on success', (done) => { 48 | getPromise(true).then((msg) => { 49 | assert.equal(msg, 'success'); 50 | done(); 51 | }); 52 | }); 53 | 54 | it('calls reject on failure', (done) => { 55 | getPromise(false).then(null, (msg) => { 56 | assert.equal(msg, 'failure'); 57 | done(); 58 | }); 59 | }); 60 | 61 | it('enters catch block on failure', (done) => { 62 | getPromise(false).then().catch(function (err) { 63 | assert.equal(err, 'failure'); 64 | done(); 65 | }) 66 | }); 67 | }); 68 | 69 | describe('early fulfillment', () => { 70 | let succeeded, failed; 71 | 72 | beforeEach(() => { 73 | succeeded = false; 74 | failed = false; 75 | }); 76 | 77 | function getPromise(success) { 78 | return new Promise((resolve, reject) => { 79 | success ? succeeded = true : failed = true; 80 | success ? resolve('success') : reject('failure'); 81 | }); 82 | } 83 | 84 | it('fulfills succesful promise before `then`', () => { 85 | getPromise(true); 86 | assert.isTrue(succeeded); 87 | assert.isFalse(failed); 88 | }); 89 | 90 | it('rejects failed promise before `then`', () => { 91 | getPromise(false); 92 | assert.isFalse(succeeded); 93 | assert.isTrue(failed); 94 | }); 95 | 96 | it('resolves succesful promise after it\'s been settled', (done) => { 97 | const p = getPromise(true); 98 | assert.isTrue(succeeded); 99 | p.then((msg) => { 100 | assert.equal(msg, 'success'); 101 | done(); 102 | }); 103 | }); 104 | 105 | it('rejects failed promise after it\'s been settled', (done) => { 106 | const p = getPromise(false); 107 | assert.isTrue(failed); 108 | p.then(null, (msg) => { 109 | assert.equal(msg, 'failure'); 110 | done(); 111 | }); 112 | }); 113 | 114 | it('enters catch block after failed promise has been settled', (done) => { 115 | const p = getPromise(false); 116 | assert.isTrue(failed); 117 | p.then().catch(function (err) { 118 | assert.equal(err, 'failure'); 119 | done(); 120 | }) 121 | }); 122 | }); 123 | 124 | describe('chained `thens`', () => { 125 | it('(resolve) returns a thennable', () => { 126 | let countCall = 0; 127 | function resolve() { 128 | countCall++; 129 | } 130 | 131 | getPromise(true).then(resolve()).then(resolve()).then(resolve()); 132 | assert.equal(countCall, 3); 133 | }); 134 | }); 135 | 136 | describe('Promise.all', () => { 137 | let r; 138 | Promise.all(['a', 'b', 'c']).then((arr) => { 139 | r = arr.map(t=>t + '1') 140 | assert.sameMembers(r, ['a1', 'b1', 'c1']); 141 | }); 142 | assert.isUndefined(r); 143 | }); 144 | 145 | describe('Promise.race', () => { 146 | const p1 = new Promise(function (resolve, reject) { 147 | setTimeout(() => resolve('p1 resolved'), 300); 148 | }); 149 | const p2 = new Promise(function (resolve, reject) { 150 | setTimeout(() => resolve('p2 resolved'), 100); 151 | }); 152 | Promise.race([p1, p2]).then(data => { 153 | assert.equal(data, 'p2 resolved'); 154 | }); 155 | }); 156 | }); 157 | 158 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "mocha": true, 6 | "node": true 7 | }, 8 | "globals": { 9 | "assert": true, 10 | "expect": true, 11 | "GeneratorFunction": true 12 | }, 13 | "rules": { 14 | // based on https://github.com/feross/standard 15 | "block-scoped-var": 0, 16 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 17 | "camelcase": 0, 18 | "comma-dangle": [2, "never"], 19 | "comma-spacing": [2, { "before": false, "after": true }], 20 | "comma-style": [2, "last"], 21 | "complexity": 0, 22 | "consistent-return": 0, 23 | "consistent-this": 0, 24 | "curly": [2, "multi-line"], 25 | "default-case": 0, 26 | "dot-notation": 0, 27 | "eol-last": 2, 28 | "eqeqeq": 0, 29 | "func-names": 0, 30 | "func-style": [0, "declaration"], 31 | "generator-star-spacing": [2, "after"], 32 | "guard-for-in": 0, 33 | "handle-callback-err": [2, "^(err|error|anySpecificError)$" ], 34 | "indent": [2, 2], 35 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 36 | "max-depth": 0, 37 | // 'max-len' deviates from 'standard' 38 | "max-len": [2, 100, 4], 39 | "max-nested-callbacks": 0, 40 | "max-params": 0, 41 | "max-statements": 0, 42 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 43 | "new-parens": 2, 44 | "no-alert": 2, 45 | "no-array-constructor": 2, 46 | "no-bitwise": 0, 47 | "no-caller": 2, 48 | "no-catch-shadow": 0, 49 | "no-cond-assign": 2, 50 | "no-console": 0, 51 | "no-constant-condition": 0, 52 | "no-control-regex": 2, 53 | "no-debugger": 2, 54 | "no-delete-var": 2, 55 | "no-div-regex": 0, 56 | "no-dupe-args": 2, 57 | "no-dupe-keys": 2, 58 | "no-duplicate-case": 2, 59 | "no-else-return": 0, 60 | "no-empty": 0, 61 | "no-empty-class": 2, 62 | "no-empty-label": 2, 63 | "no-eq-null": 0, 64 | "no-ex-assign": 2, 65 | "no-extend-native": 2, 66 | "no-extra-bind": 2, 67 | "no-extra-boolean-cast": 2, 68 | "no-extra-parens": 0, 69 | "no-extra-semi": 0, 70 | "no-extra-strict": 0, 71 | "no-fallthrough": 2, 72 | "no-floating-decimal": 2, 73 | "no-func-assign": 2, 74 | "no-implied-eval": 2, 75 | "no-inline-comments": 0, 76 | "no-inner-declarations": [2, "functions"], 77 | "no-invalid-regexp": 2, 78 | "no-irregular-whitespace": 2, 79 | "no-iterator": 2, 80 | "no-label-var": 2, 81 | "no-labels": 2, 82 | "no-lone-blocks": 0, 83 | "no-lonely-if": 0, 84 | "no-loop-func": 0, 85 | "no-mixed-requires": [0, false], 86 | "no-mixed-spaces-and-tabs": [2, false], 87 | "no-multi-spaces": 2, 88 | "no-multi-str": 2, 89 | "no-multiple-empty-lines": [2, { "max": 1 }], 90 | "no-native-reassign": 2, 91 | "no-negated-in-lhs": 2, 92 | "no-nested-ternary": 0, 93 | "no-new": 2, 94 | "no-new-func": 2, 95 | "no-new-object": 2, 96 | "no-new-require": 2, 97 | "no-new-wrappers": 2, 98 | "no-obj-calls": 2, 99 | "no-octal": 2, 100 | "no-octal-escape": 2, 101 | "no-path-concat": 0, 102 | "no-plusplus": 0, 103 | "no-process-env": 0, 104 | "no-process-exit": 0, 105 | "no-proto": 0, 106 | "no-redeclare": 2, 107 | "no-regex-spaces": 2, 108 | "no-reserved-keys": 0, 109 | "no-restricted-modules": 0, 110 | "no-return-assign": 2, 111 | "no-script-url": 2, 112 | "no-self-compare": 2, 113 | "no-sequences": 0, 114 | "no-shadow": 0, 115 | "no-shadow-restricted-names": 2, 116 | "no-spaced-func": 2, 117 | "no-sparse-arrays": 2, 118 | "no-sync": 0, 119 | "no-ternary": 0, 120 | "no-throw-literal": 2, 121 | "no-trailing-spaces": 2, 122 | "no-undef": 2, 123 | "no-undef-init": 2, 124 | "no-undefined": 0, 125 | "no-underscore-dangle": 0, 126 | "no-unreachable": 2, 127 | "no-unused-expressions": 0, 128 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 129 | "no-use-before-define": 0, 130 | "no-var": 0, 131 | "no-void": 0, 132 | "no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }], 133 | "no-with": 2, 134 | "no-wrap-func": 2, 135 | "one-var": 0, 136 | "operator-assignment": [0, "always"], 137 | "padded-blocks": [2, "never"], 138 | "quote-props": 0, 139 | "quotes": [2, "single", "avoid-escape"], 140 | "radix": 2, 141 | "semi": 0, 142 | "semi-spacing": 0, 143 | "sort-vars": 0, 144 | "space-after-keywords": [2, "always"], 145 | "space-before-blocks": [2, "always"], 146 | // 'space-before-function-parentheses' deviates from 'standard' 147 | "space-before-function-parentheses": [2, {"anonymous": "always", "named": "never"}], 148 | "space-in-brackets": 0, 149 | "space-in-parens": [2, "never"], 150 | "space-infix-ops": 2, 151 | "space-return-throw-case": 2, 152 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 153 | "spaced-line-comment": [2, "always"], 154 | "strict": 0, 155 | "use-isnan": 2, 156 | "valid-jsdoc": 0, 157 | "valid-typeof": 2, 158 | "vars-on-top": 0, 159 | // 'wrap-iife' deviates from 'standard' 160 | "wrap-iife": [0, "outside"], 161 | "wrap-regex": 0, 162 | "yoda": [2, "never"] 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tests/set.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-set-objects 2 | describe('sets', () => { 3 | describe('types', () => { 4 | it('(Set) is a constructor', () => { 5 | assert.equal(typeof Set, 'function'); 6 | assert.isDefined(Set.prototype); 7 | }); 8 | 9 | it('(set instance) is an object', () => { 10 | assert.equal(typeof new Set(), 'object'); 11 | }); 12 | }); 13 | describe('constructor parameter', () => { 14 | it('accepts null or nothing', () => { 15 | assert.isDefined(new Set(null)); 16 | assert.isDefined(new Set()); 17 | }); 18 | 19 | it('accepts any iterable', () => { 20 | const iterables = [ 21 | [1, 3, 4, 3, 6], 22 | 'abcdeffghijklmnopqrtuvwxyz', 23 | new Map([['a', 1], ['b', 2], ['a', 1], ['c', 5]]), 24 | new Set([1, 3, 4, 3, 6]), 25 | [1, 2, 3].keys(), 26 | [1, 2, 3].entries() 27 | ]; 28 | iterables.forEach((iterable) => { 29 | assert.isDefined(new Set(iterable)); 30 | }); 31 | }); 32 | 33 | it('accepts any value types', () => { 34 | const iterables = [ 35 | [1, 2, 3, 4, 8, 8], 36 | ['a', 1, 'b', 2, 'b'], 37 | [{}, [], {}, [], [], [], {}], 38 | [true, 1, false, false, 0], 39 | [Symbol(4), Symbol(4), Symbol()] 40 | ]; 41 | iterables.forEach((iterable) => { 42 | const set = new Set(iterable); 43 | assert.isDefined(set); 44 | iterable.forEach((value) => { 45 | assert.isTrue(set.has(value)); 46 | }); 47 | }); 48 | }); 49 | }); 50 | 51 | describe('set.add', () => { 52 | it('is a method', () => { 53 | const set = new Set(); 54 | assert.isDefined(set.add); 55 | assert.equal(typeof set.add, 'function'); 56 | }); 57 | 58 | it('adds values to a set', () => { 59 | const set = new Set(); 60 | const values = [1, 5, 5, 5, 4, 3, 2, 6, 4, 3, 6, 3, 3]; 61 | values.forEach(value => { 62 | set.add(value); 63 | }); 64 | values.forEach(value => { 65 | assert.isTrue(set.has(value)); 66 | }); 67 | assert.equal(set.size, 6); 68 | }); 69 | }); 70 | 71 | describe('`size` and de-duping', () => { 72 | it('defines `size`', () => { 73 | const set = new Set([1, 3, 2, 2]); 74 | assert.isDefined(set.size); 75 | assert.equal(typeof set.size, 'number'); 76 | }); 77 | 78 | it('removes duplicate values', () => { 79 | const obj = {}, arr = []; 80 | const sym1 = Symbol(), sym2 = Symbol(); 81 | const iterables = [ 82 | { 83 | value: [1, 2, 3, 4, 8, 8], 84 | unique: 5 85 | }, 86 | { 87 | value: 'abcdeffghijklmnopqrstuvwxyz', 88 | unique: 26 89 | }, 90 | { 91 | value: [obj, arr, arr, arr, obj], 92 | unique: 2 93 | }, 94 | { 95 | value: [true, 1, false, false, 0], 96 | unique: 4 97 | }, 98 | { 99 | value: [sym1, sym1, sym2], 100 | unique: 2 101 | } 102 | ]; 103 | iterables.forEach((iterable) => { 104 | const set = new Set(iterable.value); 105 | assert.equal(set.size, iterable.unique); 106 | }); 107 | }); 108 | }); 109 | 110 | describe('forEach', () => { 111 | const set = new Set([1, 3, 2, 2]); 112 | const asArray = [...set]; 113 | let count = 0; 114 | 115 | it('is a valid function', () => { 116 | assert.isDefined(set.forEach); 117 | assert.equal(typeof set.forEach, 'function'); 118 | }); 119 | 120 | it('loops over each member', () => { 121 | set.forEach((value1, value2, theSet) => { 122 | assert.equal(value1, asArray[count]); 123 | assert.equal(value2, asArray[count]); 124 | assert.equal(value1, value2); 125 | assert.equal(theSet, set); 126 | count++; 127 | }); 128 | }); 129 | }); 130 | describe('keys, values and entries', () => { 131 | const set = new Set([1, 3, 2, 2]); 132 | const asArray = [...set]; 133 | 134 | it('(they) are valid functions', () => { 135 | assert.isDefined(set.keys); 136 | assert.isDefined(set.values); 137 | assert.isDefined(set.entries); 138 | assert.equal(typeof set.keys, 'function'); 139 | assert.equal(typeof set.values, 'function'); 140 | assert.equal(typeof set.entries, 'function'); 141 | }); 142 | 143 | it('(keys and values) both iterate over the members', () => { 144 | const keysIt = set.keys(); 145 | const valuesIt = set.values(); 146 | let next, count = 0; 147 | assert.isDefined(keysIt.next); 148 | assert.isDefined(valuesIt.next); 149 | while (next = keysIt.next(), !next.done) { 150 | assert.equal(next.value, asArray[count++]); 151 | } 152 | }); 153 | 154 | it('(entires) is a matching key-value pair', () => { 155 | const entriesIt = set.entries(); 156 | let next, count = 0; 157 | assert.isDefined(entriesIt.next); 158 | while (next = entriesIt.next(), !next.done) { 159 | let member = asArray[count++]; 160 | assert.sameMembers(next.value, [member, member]); 161 | } 162 | }); 163 | }); 164 | describe('set.delete()', () => { 165 | it('defines `delete`', () => { 166 | assert.equal(typeof new Set().delete, 'function'); 167 | }); 168 | 169 | it('(`set.delete`) deletes the specified key', () => { 170 | const set = new Set([1, 5, 5, 6, 8]); 171 | assert.equal(set.size, 4); 172 | assert.isTrue(set.has(5)); 173 | set.delete(5); 174 | assert.equal(set.size, 3); 175 | assert.isFalse(set.has(5)); 176 | }); 177 | }); 178 | describe('set.clear()', () => { 179 | it('defines `clear`', () => { 180 | assert.equal(typeof new Set().clear, 'function'); 181 | }); 182 | 183 | it('(`set.clear`) empties the set', () => { 184 | const set = new Set([1, 5, 5, 6, 8]); 185 | assert.equal(set.size, 4); 186 | set.clear(); 187 | assert.equal(set.size, 0); 188 | }); 189 | }); 190 | }); 191 | -------------------------------------------------------------------------------- /tests/class.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-class-definitions 2 | describe('class', () => { 3 | class EmptyClass {}; 4 | class BasicClass { 5 | static s() {return this} 6 | a() { return this } 7 | b() {} 8 | } 9 | 10 | describe('types and properties', () => { 11 | it('is a constructor', () => { 12 | assert.equal(typeof EmptyClass, 'function'); 13 | assert.equal(typeof EmptyClass.prototype, 'object'); 14 | assert.equal(EmptyClass.prototype.constructor, EmptyClass); 15 | }); 16 | 17 | it('\'s dynamic methods go on the prototype', () => { 18 | assert.equal(typeof BasicClass.prototype.a, 'function'); 19 | assert.equal(typeof BasicClass.prototype.b, 'function'); 20 | }); 21 | 22 | it('\'s static methods go on the constructor', () => { 23 | assert.equal(typeof BasicClass.s, 'function'); 24 | }); 25 | }); 26 | 27 | describe('instances', () => { 28 | const ec = new EmptyClass(); 29 | const bc = new BasicClass(); 30 | it('(their) constructor is the class', () => { 31 | assert.equal(ec.constructor, EmptyClass); 32 | assert.equal(bc.constructor, BasicClass); 33 | }); 34 | it('(they) reference class methods in their prototype', () => { 35 | assert.equal(bc.__proto__.a, BasicClass.prototype.a); 36 | assert.equal(bc.__proto__.b, BasicClass.prototype.b); 37 | }); 38 | 39 | it('\'s value is `this` when calling prototype methods', () => { 40 | assert.equal(bc.a(), bc); 41 | }); 42 | }); 43 | 44 | describe('extends', () => { 45 | let SuperClass, SubClass; 46 | beforeEach(() => { 47 | SuperClass = class { 48 | constructor(n) { 49 | this.x = n; 50 | } 51 | c() {} 52 | d() {} 53 | e() {} 54 | } 55 | SubClass = class extends SuperClass{ 56 | constructor(n) { 57 | super(n); 58 | this.x += n; 59 | } 60 | e() {return super.e} 61 | f() {} 62 | g() {} 63 | } 64 | }); 65 | 66 | it('(the subclass) can access methods from the superclass', () => { 67 | const subClass = new SubClass(); 68 | assert.equal(typeof subClass.__proto__.e, 'function'); 69 | assert.equal(typeof subClass.__proto__.f, 'function'); 70 | assert.equal(typeof subClass.__proto__.g, 'function'); 71 | assert.equal(typeof subClass.__proto__.__proto__.c, 'function'); 72 | assert.equal(typeof subClass.__proto__.__proto__.d, 'function'); 73 | assert.equal(typeof subClass.__proto__.__proto__.e, 'function'); 74 | assert.equal(typeof subClass.c, 'function'); 75 | assert.equal(typeof subClass.d, 'function'); 76 | assert.equal(typeof subClass.e, 'function'); 77 | assert.equal(typeof subClass.f, 'function'); 78 | assert.equal(typeof subClass.g, 'function'); 79 | }); 80 | 81 | it('(the subclass) can override methods from the superclass', () => { 82 | SubClass.prototype.c = function () {}; 83 | const subClass = new SubClass(); 84 | assert.notEqual(subClass.c, subClass.__proto__.__proto__.c); 85 | }); 86 | 87 | it('can dynamically override methods from the superclass', () => { 88 | const subClass = new SubClass(); 89 | const superC = subClass.c; 90 | SubClass.prototype.c = function () {}; 91 | assert.notEqual(subClass.c, superC); 92 | }); 93 | 94 | it('uses super to access the superclass method', () => { 95 | const subClass = new SubClass(); 96 | assert.equal(typeof subClass.e, 'function'); 97 | assert.equal(typeof subClass.e(), 'function'); 98 | assert.notEqual(subClass.e, subClass.e()); 99 | }); 100 | 101 | it('(super) calls superclass constructor', () => { 102 | const subClass = new SubClass(1); 103 | assert.equal(subClass.x, 2); 104 | }); 105 | }); 106 | describe('static methods', () => { 107 | it('(they) can only be invoked by the constructor', () => { 108 | let bc = new BasicClass(); 109 | assert.isUndefined(bc.s); 110 | assert.isUndefined(BasicClass.prototype.s); 111 | assert.isDefined(BasicClass.s); 112 | }); 113 | 114 | it('(their) `this` value is the class', () => { 115 | assert.equal(BasicClass.s(), BasicClass); 116 | }); 117 | 118 | it('(they) can only see static properties', () => { 119 | class BasicClass2 { 120 | static s1() {return sp} 121 | static s2() {return this.sp} 122 | static s3() {return BasicClass2.sp} 123 | static s4() {return this.i()} 124 | i() {return 7} 125 | } 126 | BasicClass2.sp = 4; 127 | assert.throws(BasicClass2.s1, Error); 128 | assert.equal(BasicClass2.s2(), 4); 129 | assert.equal(BasicClass2.s3(), 4); 130 | assert.throws(BasicClass2.s4, Error); 131 | }); 132 | }); 133 | 134 | describe('dynamism', () => { 135 | it('can create unique classes from a template', () => { 136 | const classMaker = () => class { 137 | a() {} 138 | b() {} 139 | }; 140 | const Class1 = classMaker(); 141 | const Class2 = classMaker(); 142 | assert.notEqual(Class1, Class2); 143 | assert.notEqual(Class1.prototype.a, Class2.prototype.a); 144 | assert.notEqual(Class1.prototype.b, Class2.prototype.b); 145 | }); 146 | 147 | it('(class) can be created with different super classes', () => { 148 | const classMaker = base => class extends base {}; 149 | const Class1 = classMaker(class {a() {}}); 150 | const Class2 = classMaker(class {b() {}}); 151 | assert.notEqual(Class1, Class2); 152 | assert.isDefined(Class1.prototype.a); 153 | assert.isUndefined(Class1.b); 154 | assert.isDefined(Class2.prototype.b); 155 | assert.isUndefined(Class2.a); 156 | }); 157 | 158 | it('(class) can generate instance methods on the fly', () => { 159 | const Class1 = class {a() {}}; 160 | const class1 = new Class1(); 161 | assert.equal(class1.a, Class1.prototype.a); 162 | assert.isUndefined(class1.b); 163 | Class1.prototype.b = () => {}; 164 | assert.equal(class1.b, Class1.prototype.b); 165 | assert.isDefined(class1.b); 166 | }); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /tests/Array.spec.js: -------------------------------------------------------------------------------- 1 | describe('new array methods', () => { 2 | describe('Array.prototype methods', () => { 3 | let arr; 4 | beforeEach(() => { 5 | arr = ['a', 17, false, '30', 4]; 6 | }); 7 | 8 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.fill 9 | describe('Array.prototype.fill', () => { 10 | it('replaces all members', () => { 11 | assert.sameMembers(arr.fill(3), [3, 3, 3, 3, 3]); 12 | }); 13 | 14 | it('replaces the members up to an index', () => { 15 | assert.sameMembers(arr.fill(5, 2), ['a', 17, 5, 5, 5]); 16 | }); 17 | 18 | it('replaces the members between indices', () => { 19 | assert.sameMembers(arr.fill(5, 2, 3), ['a', 17, 5, '30', 4]); 20 | }); 21 | }); 22 | 23 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.find 24 | describe('Array.prototype.find', () => { 25 | it('finds the item', () => { 26 | assert.equal(arr.find(Number), 17); 27 | }); 28 | 29 | it('honors the `this` context', () => { 30 | assert.equal( 31 | arr.find(function (e) {return this.sqrt(e) == 2}, Math), 32 | 4 33 | ); 34 | }); 35 | }); 36 | 37 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.findindex 38 | describe('Array.prototype.findIndex', () => { 39 | it('finds the index', () => { 40 | assert.equal(arr.findIndex(Number), 1); 41 | }); 42 | 43 | it('honors the `this` context', () => { 44 | assert.equal( 45 | arr.findIndex(function (e) {return this.sqrt(e) == 2}, Math), 46 | 4 47 | ); 48 | }); 49 | }); 50 | 51 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.keys 52 | // See iterator.spec for more thorough iterator tests 53 | describe('Array.prototype.keys', () => { 54 | const arr = [7, 8, 9]; 55 | it.skip('returns an iterator', () => { 56 | assert.isDefined(arr.keys()[[Symbol.iterator]]); 57 | }); 58 | 59 | it('iterates over the keys', () => { 60 | let arrKeys = arr.keys(); 61 | let i = 0; 62 | for (let key of arrKeys) { 63 | assert.isTrue(key == i++); 64 | } 65 | }); 66 | }); 67 | 68 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.values 69 | // See iterator.spec for more thorough iterator tests 70 | describe.skip('Array.prototype.values', () => { 71 | const arr = [7, 8, 9]; 72 | it('returns an iterator', () => { 73 | assert.isDefined(arr.values()[[Symbol.iterator]]); 74 | }); 75 | 76 | it('iterates over the values', () => { 77 | let arrValues = arr.values(); 78 | let i = 0; 79 | for (let value of arrValues) { 80 | assert.isTrue(value == arr[i++]); 81 | } 82 | }); 83 | }); 84 | 85 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.entries 86 | // See iterator.spec for more thorough iterator tests 87 | describe('Array.prototype.entries', () => { 88 | const arr = [7, 8, 9]; 89 | 90 | it.skip('returns an iterator', () => { 91 | assert.isDefined(arr.entries()[[Symbol.iterator]]); 92 | }); 93 | 94 | it('iterates over the key value pairs', () => { 95 | let arrKeyValuePairs = arr.entries(); 96 | let i = 0; 97 | for (let pair of arrKeyValuePairs) { 98 | assert.sameMembers(pair, [i, arr[i]]); 99 | i++; 100 | } 101 | }); 102 | }); 103 | 104 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.copywithin 105 | describe.skip('Array.prototype.copyWithin', () => { 106 | it('copies over all members', () => { 107 | assert.sameMembers(arr.copyWithin([1, 2, 'f', 3, 4]), [1, 3, 'f', 3, 4]); 108 | }); 109 | }); 110 | }); 111 | 112 | describe('Array constructor methods', () => { 113 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from 114 | describe('Array.from', () => { 115 | it('converts array-like objects to arrays', () => { 116 | const arrayLikeObjects = [ 117 | {value: 'mickey mouse', length: 12}, 118 | {value: new Map([[true, 99], [false, window]]), length: 2}, 119 | {value: new Set([1, 'a', 'a', 4]), length: 3}, 120 | {value: (function () {return arguments})([1, 2], 6, 7, /$[0-9]*/), length: 4} 121 | ] 122 | arrayLikeObjects.forEach((obj) => { 123 | let array = Array.from(obj.value); 124 | assert.isTrue(Array.isArray(array)); 125 | assert.equal(array.length, obj.length); 126 | }); 127 | }); 128 | 129 | it('supports predicates', () => { 130 | const arr = new Array(5); 131 | arr[0] = 'x', arr[1] = 'y', arr[3] = 'z'; 132 | assert.sameMembers(Array.from(arr, e => e || '*'), ['x', 'y', '*', 'z', '*']); 133 | 134 | const predicate = (e, i, a) => Array.isArray(e) ? e[0] : e; 135 | assert.sameMembers(Array.from([1, [2, 3], 4], predicate), [1, 2, 4]); 136 | 137 | const map = new Map([[true, [1, 3, 5]], [false, [2, 4, 6]]]); 138 | const print = e => `${e[0]}-${e[1].join('')}`; 139 | assert.sameMembers(Array.from(map, print), ['true-135', 'false-246']); 140 | 141 | assert.sameMembers(Array.from({length: 3}, (e, i) => i), [0, 1, 2]); 142 | assert.sameMembers(Array.from('cow', e => e.toUpperCase()), ['C', 'O', 'W']); 143 | }); 144 | 145 | it('honors the `this` argument', () => { 146 | const sqrt = function (e) {return this.sqrt(e)} 147 | assert.sameMembers(Array.from([1, 4, 9], sqrt, Math), [1, 2, 3]); 148 | }); 149 | }); 150 | 151 | describe('Array.of', () => { 152 | it('creates a new array using the given arguments', () => { 153 | const argsData = [ 154 | [1, 2, 3], 155 | [3], 156 | ['fox', 'rabbit', 'wolf'], 157 | [{}, [], {}], 158 | [undefined] 159 | ] 160 | for (let args of argsData) { 161 | let arr = Array.of(...args); 162 | assert.equal(arr.length, args.length); 163 | args.forEach((arg, i) => { 164 | assert.equal(arr[i], arg); 165 | }); 166 | } 167 | }); 168 | }); 169 | }); 170 | }); 171 | -------------------------------------------------------------------------------- /tests/map.spec.js: -------------------------------------------------------------------------------- 1 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects 2 | describe('maps', () => { 3 | describe('types', () => { 4 | it('(Map) is a constructor', () => { 5 | assert.equal(typeof Map, 'function'); 6 | assert.isDefined(Map.prototype); 7 | }); 8 | 9 | it('(map instance) is an object', () => { 10 | assert.equal(typeof new Map(), 'object'); 11 | }); 12 | }); 13 | 14 | describe('constructor parameter', () => { 15 | it('accepts null or nothing', () => { 16 | assert.isDefined(new Map(null)); 17 | assert.isDefined(new Map()); 18 | }); 19 | 20 | it('accepts any key-value iterable', () => { 21 | const keyValueIterables = [ 22 | [['a', 1], ['b', 2]], 23 | new Map([['a', 1], ['b', 2]]), 24 | new Set([['a', 1], ['b', 2]]) 25 | ]; 26 | keyValueIterables.forEach((iterable) => { 27 | assert.isDefined(new Map(iterable)); 28 | }); 29 | }); 30 | 31 | it('accepts any types as keys or values', () => { 32 | const keyValueIterables = [ 33 | [['a', 1], ['b', 2]], 34 | [[1, 'a'], [2, 'b']], 35 | [[{}, []], [{}, []]], 36 | [[[], {}], [[], {}]], 37 | [[true, 1], [false, 0]], 38 | [[new Map([['2', 5]]), Symbol(4)], [new Map([['7', 8]]), Symbol(2)]], 39 | [[Symbol(4), new Map([['2', 5]])], [Symbol(2), new Map([['7', 8]])]] 40 | ]; 41 | keyValueIterables.forEach((iterable, c) => { 42 | const map = new Map(iterable); 43 | assert.isDefined(map); 44 | [0, 1].forEach((i) => { 45 | assert.equal( 46 | map.get(keyValueIterables[c][i][0]), 47 | keyValueIterables[c][i][1] 48 | ); 49 | }); 50 | }); 51 | }); 52 | }); 53 | 54 | describe('`set` method', () => { 55 | it('can be updated using `set`', () => { 56 | const keys = [{}, [], 1, 'a', false, Symbol(), new Date()]; 57 | const values = [1, 'a', false, Symbol(), new Date(), {}, []]; 58 | const map = new Map(); 59 | keys.forEach((key, i) => { 60 | map.set(key, values[i]); 61 | }); 62 | keys.forEach((key, i) => { 63 | assert.equal(map.get(keys[i]), values[i]); 64 | }); 65 | }); 66 | }); 67 | 68 | describe('`has` method', () => { 69 | it('checks if key is present', () => { 70 | const keys = [{}, [], 1, 'a', false, Symbol(), new Date()]; 71 | const values = [1, 'a', false, Symbol(), new Date(), {}, []]; 72 | const map = new Map(); 73 | keys.forEach((key, i) => { 74 | map.set(key, values[i]); 75 | }); 76 | keys.forEach((key, i) => { 77 | assert.isTrue(map.has(keys[i])); 78 | }); 79 | }); 80 | }); 81 | 82 | describe('map.keys()', () => { 83 | let map, keys, values; 84 | beforeEach(() => { 85 | keys = [{}, [], 1, 'a', false, Symbol(), new Date()]; 86 | values = [1, 'a', false, Symbol(), new Date(), {}, []]; 87 | map = new Map(); 88 | keys.forEach((key, i) => { 89 | map.set(key, values[i]); 90 | }); 91 | }); 92 | 93 | it('defines `keys`', () => { 94 | assert.equal(typeof map.keys, 'function'); 95 | }); 96 | 97 | it('(`map.keys`) is an iterator', () => { 98 | const keysIt = map.keys(); 99 | assert.isDefined(keysIt.next); 100 | keys.forEach((key) => { 101 | assert.equal(keysIt.next().value, key); 102 | }); 103 | }); 104 | }); 105 | 106 | describe('map.values()', () => { 107 | let map, keys, values; 108 | beforeEach(() => { 109 | keys = [{}, [], 1, 'a', false, Symbol(), new Date()]; 110 | values = [1, 'a', false, Symbol(), new Date(), {}, []]; 111 | map = new Map(); 112 | keys.forEach((key, i) => { 113 | map.set(key, values[i]); 114 | }); 115 | }); 116 | 117 | it('defines `values`', () => { 118 | assert.equal(typeof map.values, 'function'); 119 | }); 120 | 121 | it('(`map.values`) is an iterator', () => { 122 | const valuesIt = map.values(); 123 | assert.isDefined(valuesIt.next); 124 | values.forEach((value) => { 125 | assert.equal(valuesIt.next().value, value); 126 | }); 127 | }); 128 | }); 129 | 130 | describe('map.entries()', () => { 131 | let map, keys, values; 132 | beforeEach(() => { 133 | keys = [{}, [], 1, 'a', false, Symbol(), new Date()]; 134 | values = [1, 'a', false, Symbol(), new Date(), {}, []]; 135 | map = new Map(); 136 | keys.forEach((key, i) => { 137 | map.set(key, values[i]); 138 | }); 139 | }); 140 | 141 | it('defines `entries`', () => { 142 | assert.equal(typeof map.entries, 'function'); 143 | }); 144 | 145 | it('(`map.entries`) is an iterator', () => { 146 | const entriesIt = map.entries(); 147 | assert.isDefined(entriesIt.next); 148 | keys.forEach((key, i) => { 149 | assert.sameMembers(entriesIt.next().value, [key, values[i]]); 150 | }); 151 | }); 152 | }); 153 | 154 | describe('map.forEach', () => { 155 | let map, keys, values; 156 | beforeEach(() => { 157 | keys = [{}, [], 1, 'a', false, Symbol(), new Date()]; 158 | values = [1, 'a', false, Symbol(), new Date(), {}, []]; 159 | map = new Map(); 160 | keys.forEach((key, i) => { 161 | map.set(key, values[i]); 162 | }); 163 | }); 164 | 165 | it('defines `forEach`', () => { 166 | assert.equal(typeof map.forEach, 'function'); 167 | }); 168 | 169 | it('(`map.forEach`) loops through the entries', () => { 170 | let count = 0; 171 | map.forEach((value, key, mapp) => { 172 | assert.equal(value, values[count]); 173 | assert.equal(key, keys[count]); 174 | assert.equal(mapp, map); 175 | count++; 176 | }); 177 | }); 178 | }); 179 | 180 | describe('map.size', () => { 181 | it('(`map.size`) returns the number of map entries', () => { 182 | const map = new Map([['a', 1], ['b', 2]]); 183 | assert.equal(map.size, 2); 184 | map.set('c', 3); 185 | assert.equal(map.size, 3); 186 | }); 187 | }); 188 | 189 | describe('map.delete()', () => { 190 | it('defines `delete`', () => { 191 | assert.equal(typeof new Map().delete, 'function'); 192 | }); 193 | 194 | it('(`map.delete`) deletes the specified key', () => { 195 | const map = new Map([['a', 1], ['b', 2]]); 196 | assert.equal(map.size, 2); 197 | assert.isTrue(map.has('a')); 198 | map.delete('a'); 199 | assert.equal(map.size, 1); 200 | assert.isFalse(map.has('a')); 201 | }); 202 | }); 203 | 204 | describe('map.clear()', () => { 205 | it('defines `clear`', () => { 206 | assert.equal(typeof new Map().clear, 'function'); 207 | }); 208 | 209 | it('(`map.clear`) empties the map', () => { 210 | const map = new Map([['a', 1], ['b', 2]]); 211 | assert.equal(map.size, 2); 212 | map.clear(); 213 | assert.equal(map.size, 0); 214 | }); 215 | }); 216 | }); 217 | --------------------------------------------------------------------------------